linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/22] Introducing the TI Keystone platform
@ 2012-08-11  1:24 Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 01/22] ARM: add mechanism for late code patching Cyril Chemparathy
                   ` (21 more replies)
  0 siblings, 22 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy

This series is a follow on to the series posted earlier (archived at [1]).

Patches 01/22 .. 09/22 of this series have been pretty intensively reviewed;
thanks to all who helped.  We've modified per feedback, and these should be in
reasonable shape.

Patches 10/22 .. 19/22 of this series have not been very widely reviewed.
We'd very much appreciate eyeballs here.

Patches 20/22 .. 22/22 of this series are specific to the TI Keystone platform.
These are not ready to be merged in.  These are being provided here for the sake
of completeness, and to better illustrate the other patches in this series.
These are dependent on the smpops patches (see [2]).

These patches are also available on the following git repository:
git://arago-project.org/git/projects/linux-keystone.git keystone-v2


[1] - http://thread.gmane.org/gmane.linux.kernel/1336081
[2] - http://permalink.gmane.org/gmane.linux.ports.arm.kernel/171540


Series changelog:

(01/22) ARM: add mechanism for late code patching
  (v2)	pulled runtime patching code into separate source files
  (v2)	reordered arguments to patch macros for consistency with assembly
	"Rd, Rt, imm" ordering
  (v2)	added support for mov immediate patching
  (v2)	cache flush patched instructions instead of entire kernel code
  (v2)	pack patch table to reduce table volume
  (v2)	add to module vermagic to reflect abi change
  (v2)	misc. cleanups in naming and structure

(02/22) ARM: add self test for runtime patch mechanism
  (v2)	added init-time tests to verify instruction encoding

(03/22) ARM: use late patch framework for phys-virt patching
  (v2)	move __pv_offset and __pv_phys_offset to C code
  (v2)	restore conditional init of __pv_offset and __pv_phys_offset

(04/22) ARM: LPAE: use phys_addr_t on virt <--> phys conversion
  (v2)	fix patched __phys_to_virt() to use 32-bit operand
  (v2)	convert non-patch __phys_to_virt and __virt_to_phys to inlines to retain
	type checking

(05/22) ARM: LPAE: support 64-bit virt_to_phys patching
  (v2)	use phys_addr_t instead of split high/low phys_offsets
  (v2)	use mov immediate instead of add to zero when patching in high order
	physical address bits
  (v2)	fix __pv_phys_offset handling for big-endian
  (v2)	remove set_phys_offset()

(06/22) ARM: LPAE: use signed arithmetic for mask definitions
(07/22) ARM: LPAE: use phys_addr_t in alloc_init_pud()
(08/22) ARM: LPAE: use phys_addr_t in free_memmap()
  (v2)	unchanged from v1

(09/22) ARM: LPAE: use phys_addr_t for initrd location and size
  (v2)	revert to unsigned long for initrd size

(10/22) ARM: LPAE: use phys_addr_t in switch_mm()
  (v2)	use phys_addr_t instead of u64 in switch_mm()
  (v2)	revert on changes to v6 and v7-2level
  (v2)	fix register mapping for big-endian in v7-3level

(11/22) ARM: LPAE: use 64-bit accessors for TTBR registers
  (v2)	restore comment in cpu_set_reserved_ttbr0()

(12/22) ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem
(13/22) ARM: LPAE: factor out T1SZ and TTBR1 computations
  (v2)	unchanged from v1

(14/22) ARM: LPAE: accomodate >32-bit addresses for page table base
  (v2)	apply arch_pgd_shift only on lpae
  (v2)	move arch_pgd_shift definition to asm/memory.h
  (v2)	revert on changes to non-lpae procs
  (v2)	add check to ensure that the pgd physical address is aligned at an
	ARCH_PGD_SHIFT boundary

(15/22) ARM: mm: use physical addresses in highmem sanity checks
(16/22) ARM: mm: cleanup checks for membank overlap with vmalloc area
(17/22) ARM: mm: clean up membank size limit checks
(18/22) ARM: add virt_to_idmap for interconnect aliasing
  (v2)	unchanged from v1

(19/22) ARM: recreate kernel mappings in early_paging_init()
  (v2)	disable on !lpae at compile time


 arch/arm/Kconfig                                  |   36 ++++
 arch/arm/Makefile                                 |    1 +
 arch/arm/boot/dts/keystone-sim.dts                |   77 +++++++
 arch/arm/configs/keystone_defconfig               |   23 +++
 arch/arm/include/asm/mach/arch.h                  |    1 +
 arch/arm/include/asm/memory.h                     |   94 ++++++---
 arch/arm/include/asm/module.h                     |    7 +
 arch/arm/include/asm/page.h                       |    2 +-
 arch/arm/include/asm/pgtable-3level-hwdef.h       |   10 +
 arch/arm/include/asm/pgtable-3level.h             |    6 +-
 arch/arm/include/asm/proc-fns.h                   |   28 ++-
 arch/arm/include/asm/runtime-patch.h              |  175 ++++++++++++++++
 arch/arm/kernel/Makefile                          |    1 +
 arch/arm/kernel/armksyms.c                        |    4 -
 arch/arm/kernel/head.S                            |  107 +++-------
 arch/arm/kernel/module.c                          |    7 +-
 arch/arm/kernel/runtime-patch.c                   |  230 +++++++++++++++++++++
 arch/arm/kernel/setup.c                           |   18 ++
 arch/arm/kernel/smp.c                             |   11 +-
 arch/arm/kernel/vmlinux.lds.S                     |   13 +-
 arch/arm/mach-keystone/Makefile                   |    2 +
 arch/arm/mach-keystone/Makefile.boot              |    1 +
 arch/arm/mach-keystone/include/mach/debug-macro.S |   44 ++++
 arch/arm/mach-keystone/include/mach/memory.h      |   47 +++++
 arch/arm/mach-keystone/include/mach/timex.h       |   21 ++
 arch/arm/mach-keystone/include/mach/uncompress.h  |   24 +++
 arch/arm/mach-keystone/keystone.c                 |  124 +++++++++++
 arch/arm/mach-keystone/keystone.h                 |   23 +++
 arch/arm/mach-keystone/platsmp.c                  |   84 ++++++++
 arch/arm/mm/context.c                             |    9 +-
 arch/arm/mm/idmap.c                               |    4 +-
 arch/arm/mm/init.c                                |   19 +-
 arch/arm/mm/mmu.c                                 |  114 +++++++---
 arch/arm/mm/proc-v7-3level.S                      |   50 +++--
 34 files changed, 1214 insertions(+), 203 deletions(-)
 create mode 100644 arch/arm/boot/dts/keystone-sim.dts
 create mode 100644 arch/arm/configs/keystone_defconfig
 create mode 100644 arch/arm/include/asm/runtime-patch.h
 create mode 100644 arch/arm/kernel/runtime-patch.c
 create mode 100644 arch/arm/mach-keystone/Makefile
 create mode 100644 arch/arm/mach-keystone/Makefile.boot
 create mode 100644 arch/arm/mach-keystone/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-keystone/include/mach/memory.h
 create mode 100644 arch/arm/mach-keystone/include/mach/timex.h
 create mode 100644 arch/arm/mach-keystone/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-keystone/keystone.c
 create mode 100644 arch/arm/mach-keystone/keystone.h
 create mode 100644 arch/arm/mach-keystone/platsmp.c

-- 
1.7.9.5


^ permalink raw reply	[flat|nested] 44+ messages in thread

* [PATCH v2 01/22] ARM: add mechanism for late code patching
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  2:22   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 02/22] ARM: add self test for runtime patch mechanism Cyril Chemparathy
                   ` (20 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy

The original phys_to_virt/virt_to_phys patching implementation relied on early
patching prior to MMU initialization.  On PAE systems running out of >4G
address space, this would have entailed an additional round of patching after
switching over to the high address space.

The approach implemented here conceptually extends the original PHYS_OFFSET
patching implementation with the introduction of "early" patch stubs.  Early
patch code is required to be functional out of the box, even before the patch
is applied.  This is implemented by inserting functional (but inefficient)
load code into the .runtime.patch.code init section.  Having functional code
out of the box then allows us to defer the init time patch application until
later in the init sequence.

In addition to fitting better with our need for physical address-space
switch-over, this implementation should be somewhat more extensible by virtue
of its more readable (and hackable) C implementation.  This should prove
useful for other similar init time specialization needs, especially in light
of our multi-platform kernel initiative.

This code has been boot tested in both ARM and Thumb-2 modes on an ARMv7
(Cortex-A8) device.

Note: the obtuse use of stringified symbols in patch_stub() and
early_patch_stub() is intentional.  Theoretically this should have been
accomplished with formal operands passed into the asm block, but this requires
the use of the 'c' modifier for instantiating the long (e.g. .long %c0).
However, the 'c' modifier has been found to ICE certain versions of GCC, and
therefore we resort to stringified symbols here.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/Kconfig                     |    3 +
 arch/arm/include/asm/module.h        |    7 ++
 arch/arm/include/asm/runtime-patch.h |  175 +++++++++++++++++++++++++++++++
 arch/arm/kernel/Makefile             |    1 +
 arch/arm/kernel/module.c             |    4 +
 arch/arm/kernel/runtime-patch.c      |  189 ++++++++++++++++++++++++++++++++++
 arch/arm/kernel/setup.c              |    3 +
 arch/arm/kernel/vmlinux.lds.S        |   10 ++
 8 files changed, 392 insertions(+)
 create mode 100644 arch/arm/include/asm/runtime-patch.h
 create mode 100644 arch/arm/kernel/runtime-patch.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index e91c7cd..d0a04ad 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -61,6 +61,9 @@ config ARM
 config ARM_HAS_SG_CHAIN
 	bool
 
+config ARM_RUNTIME_PATCH
+	bool
+
 config NEED_SG_DMA_LENGTH
 	bool
 
diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
index 6c6809f..2090486 100644
--- a/arch/arm/include/asm/module.h
+++ b/arch/arm/include/asm/module.h
@@ -43,9 +43,16 @@ struct mod_arch_specific {
 #define MODULE_ARCH_VERMAGIC_ARMTHUMB ""
 #endif
 
+#ifdef CONFIG_ARM_RUNTIME_PATCH
+#define MODULE_ARCH_VERMAGIC_RT_PATCH "rt-patch "
+#else
+#define MODULE_ARCH_VERMAGIC_RT_PATCH ""
+#endif
+
 #define MODULE_ARCH_VERMAGIC \
 	MODULE_ARCH_VERMAGIC_ARMVSN \
 	MODULE_ARCH_VERMAGIC_ARMTHUMB \
+	MODULE_ARCH_VERMAGIC_RT_PATCH \
 	MODULE_ARCH_VERMAGIC_P2V
 
 #endif /* _ASM_ARM_MODULE_H */
diff --git a/arch/arm/include/asm/runtime-patch.h b/arch/arm/include/asm/runtime-patch.h
new file mode 100644
index 0000000..6c6e8a2
--- /dev/null
+++ b/arch/arm/include/asm/runtime-patch.h
@@ -0,0 +1,175 @@
+/*
+ * arch/arm/include/asm/runtime-patch.h
+ * Note: this file should not be included by non-asm/.h files
+ *
+ * Copyright 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_ARM_RUNTIME_PATCH_H
+#define __ASM_ARM_RUNTIME_PATCH_H
+
+#include <linux/stringify.h>
+
+#ifndef __ASSEMBLY__
+
+#ifdef CONFIG_ARM_RUNTIME_PATCH
+
+struct patch_info {
+	void	*insn;
+	u16	 type;
+	u8	 insn_size;
+	u8	 data_size;
+	u32	 data[0];
+};
+
+#define patch_next(p)		((void *)(p) + sizeof(*(p)) + (p)->data_size)
+
+#define PATCH_TYPE_MASK		0x00ff
+#define PATCH_IMM8		0x0001
+
+#define PATCH_EARLY		0x8000
+
+#define patch_stub(type, code, patch_data, ...)				\
+	__asm__("@ patch stub\n"					\
+		"1:\n"							\
+		code							\
+		"2:\n"							\
+		"	.pushsection .runtime.patch.table, \"a\"\n"	\
+		"3:\n"							\
+		"	.word 1b\n"					\
+		"	.hword (" __stringify(type) ")\n"		\
+		"	.byte (2b-1b)\n"				\
+		"	.byte (5f-4f)\n"				\
+		"4:\n"							\
+		patch_data						\
+		"	.align\n"					\
+		"5:\n"							\
+		"	.popsection\n"					\
+		__VA_ARGS__)
+
+#define early_patch_stub(type, code, patch_data, ...)			\
+	__asm__("@ patch stub\n"					\
+		"1:\n"							\
+		"	b	6f\n"					\
+		"2:\n"							\
+		"	.pushsection .runtime.patch.table, \"a\"\n"	\
+		"3:\n"							\
+		"	.word 1b\n"					\
+		"	.hword (" __stringify(type | PATCH_EARLY) ")\n"	\
+		"	.byte (2b-1b)\n"				\
+		"	.byte (5f-4f)\n"				\
+		"4:\n"							\
+		patch_data						\
+		"	.align\n"					\
+		"5:\n"							\
+		"	.popsection\n"					\
+		"	.pushsection .runtime.patch.code, \"ax\"\n"	\
+		"6:\n"							\
+		code							\
+		"	b 2b\n"						\
+		"	.popsection\n"					\
+		__VA_ARGS__)
+
+/* constant used to force encoding */
+#define __IMM8		(0x81 << 24)
+
+/*
+ * patch_imm8() - init-time specialized binary operation (imm8 operand)
+ *		  This effectively does: to = from "insn" sym,
+ *		  where the value of sym is fixed at init-time, and is patched
+ *		  in as an immediate operand.  This value must be
+ *		  representible as an 8-bit quantity with an optional
+ *		  rotation.
+ *
+ *		  The stub code produced by this variant is non-functional
+ *		  prior to patching.  Use early_patch_imm8() if you need the
+ *		  code to be functional early on in the init sequence.
+ */
+#define patch_imm8(insn, to, from, sym, offset)				\
+	patch_stub(PATCH_IMM8,						\
+		   /* code */						\
+		   insn " %0, %1, %2\n",				\
+		   /* patch_data */					\
+		   ".long " __stringify(sym + offset) "\n"		\
+		   insn " %0, %1, %2\n",				\
+		   : "=r" (to)						\
+		   : "r" (from), "I" (__IMM8), "m" (sym)		\
+		   : "cc")
+
+/*
+ * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
+ */
+#define patch_imm8_mov(insn, to, sym, offset)				\
+	patch_stub(PATCH_IMM8,						\
+		   /* code */						\
+		   insn " %0, %1\n",					\
+		   /* patch_data */					\
+		   ".long " __stringify(sym + offset) "\n"		\
+		   insn " %0, %1\n",					\
+		   : "=r" (to)						\
+		   : "I" (__IMM8), "m" (sym)				\
+		   : "cc")
+
+/*
+ * early_patch_imm8() - early functional variant of patch_imm8() above.  The
+ *			same restrictions on the constant apply here.  This
+ *			version emits workable (albeit inefficient) code at
+ *			compile-time, and therefore functions even prior to
+ *			patch application.
+ */
+#define early_patch_imm8(insn, to, from, sym, offset)			\
+	early_patch_stub(PATCH_IMM8,					\
+			 /* code */					\
+			 "ldr	%0, =" __stringify(sym + offset) "\n"	\
+			 "ldr	%0, [%0]\n"				\
+			 insn " %0, %1, %0\n",				\
+			 /* patch_data */				\
+			 ".long " __stringify(sym + offset) "\n"	\
+			 insn " %0, %1, %2\n",				\
+			 : "=&r" (to)					\
+			 : "r" (from), "I" (__IMM8), "m" (sym)		\
+			 : "cc")
+
+#define early_patch_imm8_mov(insn, to, sym, offset)			\
+	early_patch_stub(PATCH_IMM8,					\
+			 /* code */					\
+			 "ldr	%0, =" __stringify(sym + offset) "\n"	\
+			 "ldr	%0, [%0]\n"				\
+			 insn " %0, %0\n",				\
+			 /* patch_data */				\
+			 ".long " __stringify(sym + offset) "\n"	\
+			 insn " %0, %1\n",				\
+			 : "=&r" (to)					\
+			 : "I" (__IMM8), "m" (sym)			\
+			 : "cc")
+
+int runtime_patch(const void *table, unsigned size);
+void runtime_patch_kernel(void);
+
+#else
+
+static inline int runtime_patch(const void *table, unsigned size)
+{
+	return 0;
+}
+
+static inline void runtime_patch_kernel(void)
+{
+}
+
+#endif /* CONFIG_ARM_RUNTIME_PATCH */
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* __ASM_ARM_RUNTIME_PATCH_H */
diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
index 7ad2d5c..12cc1e7 100644
--- a/arch/arm/kernel/Makefile
+++ b/arch/arm/kernel/Makefile
@@ -81,5 +81,6 @@ endif
 head-y			:= head$(MMUEXT).o
 obj-$(CONFIG_DEBUG_LL)	+= debug.o
 obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
+obj-$(CONFIG_ARM_RUNTIME_PATCH)	+= runtime-patch.o
 
 extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1e9be5d..dcebf80 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -24,6 +24,7 @@
 #include <asm/sections.h>
 #include <asm/smp_plat.h>
 #include <asm/unwind.h>
+#include <asm/runtime-patch.h>
 
 #ifdef CONFIG_XIP_KERNEL
 /*
@@ -321,6 +322,9 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 	if (s)
 		fixup_pv_table((void *)s->sh_addr, s->sh_size);
 #endif
+	s = find_mod_section(hdr, sechdrs, ".runtime.patch.table");
+	if (s)
+		runtime_patch((void *)s->sh_addr, s->sh_size);
 	s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
 	if (s && !is_smp())
 #ifdef CONFIG_SMP_ON_UP
diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
new file mode 100644
index 0000000..fd37a2b
--- /dev/null
+++ b/arch/arm/kernel/runtime-patch.c
@@ -0,0 +1,189 @@
+/*
+ * arch/arm/kernel/runtime-patch.c
+ *
+ * Copyright 2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/kernel.h>
+#include <linux/sched.h>
+
+#include <asm/opcodes.h>
+#include <asm/cacheflush.h>
+#include <asm/runtime-patch.h>
+
+static inline void flush_icache_insn(void *insn_ptr, int bytes)
+{
+	unsigned long insn_addr = (unsigned long)insn_ptr;
+	flush_icache_range(insn_addr, insn_addr + bytes - 1);
+}
+
+#ifdef CONFIG_THUMB2_KERNEL
+
+static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
+{
+	u32 op, rot, val;
+	const u32 supported_ops = (BIT(0)  | /* and */
+				   BIT(1)  | /* bic */
+				   BIT(2)  | /* orr/mov */
+				   BIT(3)  | /* orn/mvn */
+				   BIT(4)  | /* eor */
+				   BIT(8)  | /* add */
+				   BIT(10) | /* adc */
+				   BIT(11) | /* sbc */
+				   BIT(12) | /* sub */
+				   BIT(13)); /* rsb */
+
+	insn = __mem_to_opcode_thumb32(insn);
+
+	if (!__opcode_is_thumb32(insn)) {
+		pr_err("patch: invalid thumb2 insn %08x\n", insn);
+		return -EINVAL;
+	}
+
+	/* allow only data processing (immediate)
+	 * 1111 0x0x xxx0 xxxx 0xxx xxxx xxxx xxxx */
+	if ((insn & 0xfa008000) != 0xf0000000) {
+		pr_err("patch: unknown insn %08x\n", insn);
+		return -EINVAL;
+	}
+
+	/* extract op code */
+	op = (insn >> 21) & 0xf;
+
+	/* disallow unsupported opcodes */
+	if ((supported_ops & BIT(op)) == 0) {
+		pr_err("patch: unsupported opcode %x\n", op);
+		return -EINVAL;
+	}
+
+	if (imm <= 0xff) {
+		rot = 0;
+		val = imm;
+	} else {
+		rot = 32 - fls(imm); /* clz */
+		if (imm & ~(0xff000000 >> rot)) {
+			pr_err("patch: constant overflow %08x\n", imm);
+			return -EINVAL;
+		}
+		val  = (imm >> (24 - rot)) & 0x7f;
+		rot += 8; /* encoded i:imm3:a */
+
+		/* pack least-sig rot bit into most-sig val bit */
+		val |= (rot & 1) << 7;
+		rot >>= 1;
+	}
+
+	*ninsn  = insn & ~(BIT(26) | 0x7 << 12 | 0xff);
+	*ninsn |= (rot >> 3) << 26;	/* field "i" */
+	*ninsn |= (rot & 0x7) << 12;	/* field "imm3" */
+	*ninsn |= val;
+	*ninsn  = __opcode_to_mem_thumb32(*ninsn);
+
+	return 0;
+}
+
+#else
+
+static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
+{
+	u32 rot, val, op;
+
+	insn = __mem_to_opcode_arm(insn);
+
+	/* disallow special unconditional instructions
+	 * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx */
+	if ((insn >> 24) == 0xf) {
+		pr_err("patch: unconditional insn %08x\n", insn);
+		return -EINVAL;
+	}
+
+	/* allow only data processing (immediate)
+	 * xxxx 001x xxxx xxxx xxxx xxxx xxxx xxxx */
+	if (((insn >> 25) & 0x3) != 1) {
+		pr_err("patch: unknown insn %08x\n", insn);
+		return -EINVAL;
+	}
+
+	/* extract op code */
+	op = (insn >> 20) & 0x1f;
+
+	/* disallow unsupported 10xxx op codes */
+	if (((op >> 3) & 0x3) == 2) {
+		pr_err("patch: unsupported opcode %08x\n", insn);
+		return -EINVAL;
+	}
+
+	rot = imm ? __ffs(imm) / 2 : 0;
+	val = imm >> (rot * 2);
+	rot = (-rot) & 0xf;
+
+	/* does this fit in 8-bit? */
+	if (val > 0xff) {
+		pr_err("patch: constant overflow %08x\n", imm);
+		return -EINVAL;
+	}
+
+	/* patch in new immediate and rotation */
+	*ninsn = (insn & ~0xfff) | (rot << 8) | val;
+	*ninsn = __opcode_to_mem_arm(*ninsn);
+
+	return 0;
+}
+
+#endif	/* CONFIG_THUMB2_KERNEL */
+
+static int apply_patch_imm8(const struct patch_info *p)
+{
+	u32 *insn_ptr = p->insn;
+	int ret;
+
+	if (p->insn_size != sizeof(u32) || p->data_size != 2 * sizeof(u32)) {
+		pr_err("patch: bad patch, insn size %d, data size %d\n",
+		       p->insn_size, p->data_size);
+		return -EINVAL;
+	}
+
+	ret = do_patch_imm8(p->data[1], *(u32 *)p->data[0], insn_ptr);
+	if (ret < 0)
+		return ret;
+
+	flush_icache_insn(insn_ptr, sizeof(u32));
+
+	return 0;
+}
+
+int runtime_patch(const void *table, unsigned size)
+{
+	const struct patch_info *p = table, *end = (table + size);
+
+	for (p = table; p < end; p = patch_next(p)) {
+		int type = p->type & PATCH_TYPE_MASK;
+		int ret = -EINVAL;
+
+		if (type == PATCH_IMM8)
+			ret = apply_patch_imm8(p);
+		if (ret < 0)
+			return ret;
+	}
+	return 0;
+}
+
+void __init runtime_patch_kernel(void)
+{
+	extern unsigned __runtime_patch_table_begin, __runtime_patch_table_end;
+	const void *start = &__runtime_patch_table_begin;
+	const void *end   = &__runtime_patch_table_end;
+
+	BUG_ON(runtime_patch(start, end - start));
+}
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index a81dcec..669bbf0 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -55,6 +55,7 @@
 #include <asm/traps.h>
 #include <asm/unwind.h>
 #include <asm/memblock.h>
+#include <asm/runtime-patch.h>
 
 #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
 #include "compat.h"
@@ -998,6 +999,8 @@ void __init setup_arch(char **cmdline_p)
 
 	if (mdesc->init_early)
 		mdesc->init_early();
+
+	runtime_patch_kernel();
 }
 
 
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index 36ff15b..ea35ca0 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -167,6 +167,16 @@ SECTIONS
 		*(.pv_table)
 		__pv_table_end = .;
 	}
+	.init.runtime_patch_table : {
+		__runtime_patch_table_begin = .;
+		*(.runtime.patch.table)
+		__runtime_patch_table_end = .;
+	}
+	.init.runtime_patch_code : {
+		__runtime_patch_code_begin = .;
+		*(.runtime.patch.code)
+		__runtime_patch_code_end = .;
+	}
 	.init.data : {
 #ifndef CONFIG_XIP_KERNEL
 		INIT_DATA
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 02/22] ARM: add self test for runtime patch mechanism
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 01/22] ARM: add mechanism for late code patching Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  2:35   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
                   ` (19 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy

This patch adds basic sanity tests to ensure that the instruction patching
results in valid instruction encodings.  This is done by verifying the output
of the patch process against a vector of assembler generated instructions at
init time.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/Kconfig                |   12 ++++++++++++
 arch/arm/kernel/runtime-patch.c |   41 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 53 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index d0a04ad..7e552dc 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -211,6 +211,18 @@ config ARM_PATCH_PHYS_VIRT
 	  this feature (eg, building a kernel for a single machine) and
 	  you need to shrink the kernel to the minimal size.
 
+config ARM_RUNTIME_PATCH_TEST
+	bool "Self test runtime patching mechanism" if ARM_RUNTIME_PATCH
+	default y
+	help
+	  Select this to enable init time self checking for the runtime kernel
+	  patching mechanism.  This enables an ISA specific set of tests that
+	  ensure that the instructions generated by the patch process are
+	  consistent with those generated by the assembler at compile time.
+
+	  Only disable this option if you need to shrink the kernel to the
+	  minimal size.
+
 config NEED_MACH_IO_H
 	bool
 	help
diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
index fd37a2b..c471d8c 100644
--- a/arch/arm/kernel/runtime-patch.c
+++ b/arch/arm/kernel/runtime-patch.c
@@ -163,6 +163,44 @@ static int apply_patch_imm8(const struct patch_info *p)
 	return 0;
 }
 
+#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST
+static void __init __used __naked __patch_test_code_imm8(void)
+{
+	__asm__ __volatile__ (
+		"	.irp	shift1, 0, 6, 12, 18\n"
+		"	.irp	shift2, 0, 1, 2, 3, 4, 5\n"
+		"	add     r1, r2, #(0x41 << (\\shift1 + \\shift2))\n"
+		"	.endr\n"
+		"	.endr\n"
+		"	.word	0\n"
+		: : :
+	);
+}
+
+static void __init test_patch_imm8(void)
+{
+	u32 test_code_addr = (u32)(&__patch_test_code_imm8);
+	u32 *test_code = (u32 *)(test_code_addr & ~0x3);
+	int i, ret;
+	u32 ninsn, insn;
+
+	insn = test_code[0];
+	for (i = 0; test_code[i]; i++) {
+		ret = do_patch_imm8(insn, 0x41 << i, &ninsn);
+		if (ret < 0)
+			pr_err("runtime patch (imm8): failed at shift %d\n", i);
+		else if (ninsn != test_code[i])
+			pr_err("runtime patch (imm8): failed, need %x got %x\n",
+			       test_code[i], ninsn);
+	}
+}
+
+static void __init runtime_patch_test(void)
+{
+	test_patch_imm8();
+}
+#endif
+
 int runtime_patch(const void *table, unsigned size)
 {
 	const struct patch_info *p = table, *end = (table + size);
@@ -185,5 +223,8 @@ void __init runtime_patch_kernel(void)
 	const void *start = &__runtime_patch_table_begin;
 	const void *end   = &__runtime_patch_table_end;
 
+#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST
+	runtime_patch_test();
+#endif
 	BUG_ON(runtime_patch(start, end - start));
 }
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 01/22] ARM: add mechanism for late code patching Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 02/22] ARM: add self test for runtime patch mechanism Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  3:03   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
                   ` (18 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy

This patch replaces the original physical offset patching implementation
with one that uses the newly added patching framework.  In the process, we now
unconditionally initialize the __pv_phys_offset and __pv_offset globals in the
head.S code.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/Kconfig              |    1 +
 arch/arm/include/asm/memory.h |   26 +++--------
 arch/arm/kernel/armksyms.c    |    4 --
 arch/arm/kernel/head.S        |   95 +++++++----------------------------------
 arch/arm/kernel/module.c      |    5 ---
 arch/arm/kernel/setup.c       |   12 ++++++
 arch/arm/kernel/vmlinux.lds.S |    5 ---
 7 files changed, 36 insertions(+), 112 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 7e552dc..9ac86ea 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -199,6 +199,7 @@ config ARM_PATCH_PHYS_VIRT
 	default y
 	depends on !XIP_KERNEL && MMU
 	depends on !ARCH_REALVIEW || !SPARSEMEM
+	select ARM_RUNTIME_PATCH
 	help
 	  Patch phys-to-virt and virt-to-phys translation functions at
 	  boot and module load time according to the position of the
diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index e965f1b..3d93779 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -18,6 +18,8 @@
 #include <linux/types.h>
 #include <linux/sizes.h>
 
+#include <asm/runtime-patch.h>
+
 #ifdef CONFIG_NEED_MACH_MEMORY_H
 #include <mach/memory.h>
 #endif
@@ -151,35 +153,21 @@
 #ifndef __virt_to_phys
 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
 
-/*
- * Constants used to force the right instruction encodings and shifts
- * so that all we need to do is modify the 8-bit constant field.
- */
-#define __PV_BITS_31_24	0x81000000
-
-extern unsigned long __pv_phys_offset;
-#define PHYS_OFFSET __pv_phys_offset
-
-#define __pv_stub(from,to,instr,type)			\
-	__asm__("@ __pv_stub\n"				\
-	"1:	" instr "	%0, %1, %2\n"		\
-	"	.pushsection .pv_table,\"a\"\n"		\
-	"	.long	1b\n"				\
-	"	.popsection\n"				\
-	: "=r" (to)					\
-	: "r" (from), "I" (type))
+extern unsigned long	__pv_offset;
+extern unsigned long	__pv_phys_offset;
+#define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
 
 static inline unsigned long __virt_to_phys(unsigned long x)
 {
 	unsigned long t;
-	__pv_stub(x, t, "add", __PV_BITS_31_24);
+	early_patch_imm8("add", t, x, __pv_offset, 0);
 	return t;
 }
 
 static inline unsigned long __phys_to_virt(unsigned long x)
 {
 	unsigned long t;
-	__pv_stub(x, t, "sub", __PV_BITS_31_24);
+	early_patch_imm8("sub", t, x, __pv_offset, 0);
 	return t;
 }
 #else
diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
index 60d3b73..6b388f8 100644
--- a/arch/arm/kernel/armksyms.c
+++ b/arch/arm/kernel/armksyms.c
@@ -152,7 +152,3 @@ EXPORT_SYMBOL(mcount);
 #endif
 EXPORT_SYMBOL(__gnu_mcount_nc);
 #endif
-
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
-EXPORT_SYMBOL(__pv_phys_offset);
-#endif
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 3db960e..69a3c09 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -117,7 +117,7 @@ ENTRY(stext)
 	bl	__fixup_smp
 #endif
 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
-	bl	__fixup_pv_table
+	bl	__fixup_pv_offsets
 #endif
 	bl	__create_page_tables
 
@@ -511,92 +511,29 @@ ENDPROC(fixup_smp)
 
 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
 
-/* __fixup_pv_table - patch the stub instructions with the delta between
- * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
- * can be expressed by an immediate shifter operand. The stub instruction
- * has a form of '(add|sub) rd, rn, #imm'.
+/*
+ * __fixup_pv_offsets - update __pv_offset and __pv_phys_offset based on the
+ * runtime location of the kernel.
  */
 	__HEAD
-__fixup_pv_table:
+__fixup_pv_offsets:
 	adr	r0, 1f
-	ldmia	r0, {r3-r5, r7}
+	ldmia	r0, {r3-r6}
 	sub	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET
-	add	r4, r4, r3	@ adjust table start address
-	add	r5, r5, r3	@ adjust table end address
-	add	r7, r7, r3	@ adjust __pv_phys_offset address
-	str	r8, [r7]	@ save computed PHYS_OFFSET to __pv_phys_offset
-	mov	r6, r3, lsr #24	@ constant for add/sub instructions
-	teq	r3, r6, lsl #24 @ must be 16MiB aligned
-THUMB(	it	ne		@ cross section branch )
-	bne	__error
-	str	r6, [r7, #4]	@ save to __pv_offset
-	b	__fixup_a_pv_table
-ENDPROC(__fixup_pv_table)
+	add	r4, r4, r3	@ virt_to_phys(__pv_phys_offset)
+	add	r5, r5, r3	@ virt_to_phys(__pv_offset)
+	add	r6, r6, r3	@ virt_to_phys(PAGE_OFFSET) = PHYS_OFFSET
+	str	r6, [r4]	@ save __pv_phys_offset
+	str	r3, [r5]	@ save __pv_offset
+	mov	pc, lr
+ENDPROC(__fixup_pv_offsets)
 
 	.align
 1:	.long	.
-	.long	__pv_table_begin
-	.long	__pv_table_end
-2:	.long	__pv_phys_offset
-
-	.text
-__fixup_a_pv_table:
-#ifdef CONFIG_THUMB2_KERNEL
-	lsls	r6, #24
-	beq	2f
-	clz	r7, r6
-	lsr	r6, #24
-	lsl	r6, r7
-	bic	r6, #0x0080
-	lsrs	r7, #1
-	orrcs	r6, #0x0080
-	orr	r6, r6, r7, lsl #12
-	orr	r6, #0x4000
-	b	2f
-1:	add     r7, r3
-	ldrh	ip, [r7, #2]
-	and	ip, 0x8f00
-	orr	ip, r6	@ mask in offset bits 31-24
-	strh	ip, [r7, #2]
-2:	cmp	r4, r5
-	ldrcc	r7, [r4], #4	@ use branch for delay slot
-	bcc	1b
-	bx	lr
-#else
-	b	2f
-1:	ldr	ip, [r7, r3]
-	bic	ip, ip, #0x000000ff
-	orr	ip, ip, r6	@ mask in offset bits 31-24
-	str	ip, [r7, r3]
-2:	cmp	r4, r5
-	ldrcc	r7, [r4], #4	@ use branch for delay slot
-	bcc	1b
-	mov	pc, lr
+	.long	__pv_phys_offset
+	.long	__pv_offset
+	.long	PAGE_OFFSET
 #endif
-ENDPROC(__fixup_a_pv_table)
-
-ENTRY(fixup_pv_table)
-	stmfd	sp!, {r4 - r7, lr}
-	ldr	r2, 2f			@ get address of __pv_phys_offset
-	mov	r3, #0			@ no offset
-	mov	r4, r0			@ r0 = table start
-	add	r5, r0, r1		@ r1 = table size
-	ldr	r6, [r2, #4]		@ get __pv_offset
-	bl	__fixup_a_pv_table
-	ldmfd	sp!, {r4 - r7, pc}
-ENDPROC(fixup_pv_table)
 
-	.align
-2:	.long	__pv_phys_offset
-
-	.data
-	.globl	__pv_phys_offset
-	.type	__pv_phys_offset, %object
-__pv_phys_offset:
-	.long	0
-	.size	__pv_phys_offset, . - __pv_phys_offset
-__pv_offset:
-	.long	0
-#endif
 
 #include "head-common.S"
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index dcebf80..ac13dd5 100644
--- a/arch/arm/kernel/module.c
+++ b/arch/arm/kernel/module.c
@@ -317,11 +317,6 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 					         maps[i].txt_sec->sh_addr,
 					         maps[i].txt_sec->sh_size);
 #endif
-#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
-	s = find_mod_section(hdr, sechdrs, ".pv_table");
-	if (s)
-		fixup_pv_table((void *)s->sh_addr, s->sh_size);
-#endif
 	s = find_mod_section(hdr, sechdrs, ".runtime.patch.table");
 	if (s)
 		runtime_patch((void *)s->sh_addr, s->sh_size);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 669bbf0..59e0f57 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -152,6 +152,18 @@ static union { char c[4]; unsigned long l; } endian_test __initdata = { { 'l', '
 
 DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
 
+#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
+
+/*
+ * These are initialized in head.S code prior to BSS getting cleared out.
+ * The initializers here prevent these from landing in the BSS section.
+ */
+unsigned long __pv_offset = 0xdeadbeef;
+unsigned long __pv_phys_offset = 0xdeadbeef;
+EXPORT_SYMBOL(__pv_phys_offset);
+
+#endif
+
 /*
  * Standard memory resources
  */
diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
index ea35ca0..2080111 100644
--- a/arch/arm/kernel/vmlinux.lds.S
+++ b/arch/arm/kernel/vmlinux.lds.S
@@ -162,11 +162,6 @@ SECTIONS
 		__smpalt_end = .;
 	}
 #endif
-	.init.pv_table : {
-		__pv_table_begin = .;
-		*(.pv_table)
-		__pv_table_end = .;
-	}
 	.init.runtime_patch_table : {
 		__runtime_patch_table_begin = .;
 		*(.runtime.patch.table)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (2 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  3:04   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
                   ` (17 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch fixes up the types used when converting back and forth between
physical and virtual addresses.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/include/asm/memory.h |   26 ++++++++++++++++++--------
 1 file changed, 18 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 3d93779..81e1714 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -157,22 +157,32 @@ extern unsigned long	__pv_offset;
 extern unsigned long	__pv_phys_offset;
 #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
 
-static inline unsigned long __virt_to_phys(unsigned long x)
+static inline phys_addr_t __virt_to_phys(unsigned long x)
 {
 	unsigned long t;
 	early_patch_imm8("add", t, x, __pv_offset, 0);
 	return t;
 }
 
-static inline unsigned long __phys_to_virt(unsigned long x)
+static inline unsigned long __phys_to_virt(phys_addr_t x)
 {
-	unsigned long t;
-	early_patch_imm8("sub", t, x, __pv_offset, 0);
+	unsigned long t, xlo = x;
+	early_patch_imm8("sub", t, xlo, __pv_offset, 0);
 	return t;
 }
+
 #else
-#define __virt_to_phys(x)	((x) - PAGE_OFFSET + PHYS_OFFSET)
-#define __phys_to_virt(x)	((x) - PHYS_OFFSET + PAGE_OFFSET)
+
+static inline phys_addr_t __virt_to_phys(unsigned long x)
+{
+	return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
+}
+
+static inline unsigned long __phys_to_virt(phys_addr_t x)
+{
+	return x - PHYS_OFFSET + PAGE_OFFSET;
+}
+
 #endif
 #endif
 
@@ -207,14 +217,14 @@ static inline phys_addr_t virt_to_phys(const volatile void *x)
 
 static inline void *phys_to_virt(phys_addr_t x)
 {
-	return (void *)(__phys_to_virt((unsigned long)(x)));
+	return (void *)__phys_to_virt(x);
 }
 
 /*
  * Drivers should NOT use these either.
  */
 #define __pa(x)			__virt_to_phys((unsigned long)(x))
-#define __va(x)			((void *)__phys_to_virt((unsigned long)(x)))
+#define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
 /*
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (3 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  3:39   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
                   ` (16 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy

This patch adds support for 64-bit physical addresses in virt_to_phys()
patching.  This does not do real 64-bit add/sub, but instead patches in the
upper 32-bits of the phys_offset directly into the output of virt_to_phys.

There is no corresponding change on the phys_to_virt() side, because
computations on the upper 32-bits would be discarded anyway.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/include/asm/memory.h |   22 ++++++++++++++++++----
 arch/arm/kernel/head.S        |    4 ++++
 arch/arm/kernel/setup.c       |    2 +-
 3 files changed, 23 insertions(+), 5 deletions(-)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 81e1714..dc5fbf3 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -154,14 +154,28 @@
 #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
 
 extern unsigned long	__pv_offset;
-extern unsigned long	__pv_phys_offset;
+extern phys_addr_t	__pv_phys_offset;
 #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
 
 static inline phys_addr_t __virt_to_phys(unsigned long x)
 {
-	unsigned long t;
-	early_patch_imm8("add", t, x, __pv_offset, 0);
-	return t;
+	unsigned long tlo, thi;
+
+	early_patch_imm8("add", tlo, x, __pv_offset, 0);
+
+#ifdef CONFIG_ARM_LPAE
+	/*
+	 * On LPAE, we do not _need_ to do 64-bit arithmetic because the high
+	 * order 32 bits are never changed by the phys-virt offset.  We simply
+	 * patch in the high order physical address bits instead.
+	 */
+#ifdef __ARMEB__
+	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
+#else
+	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
+#endif
+#endif
+	return (u64)tlo | (u64)thi << 32;
 }
 
 static inline unsigned long __phys_to_virt(phys_addr_t x)
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 69a3c09..61fb8df 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -530,7 +530,11 @@ ENDPROC(__fixup_pv_offsets)
 
 	.align
 1:	.long	.
+#if defined(CONFIG_ARM_LPAE) && defined(__ARMEB__)
+	.long	__pv_phys_offset + 4
+#else
 	.long	__pv_phys_offset
+#endif
 	.long	__pv_offset
 	.long	PAGE_OFFSET
 #endif
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index 59e0f57..edb4f42 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -159,7 +159,7 @@ DEFINE_PER_CPU(struct cpuinfo_arm, cpu_data);
  * The initializers here prevent these from landing in the BSS section.
  */
 unsigned long __pv_offset = 0xdeadbeef;
-unsigned long __pv_phys_offset = 0xdeadbeef;
+phys_addr_t   __pv_phys_offset = 0xdeadbeef;
 EXPORT_SYMBOL(__pv_phys_offset);
 
 #endif
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (4 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  3:57   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 07/22] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
                   ` (15 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch applies to PAGE_MASK, PMD_MASK, and PGDIR_MASK, where forcing
unsigned long math truncates the mask at the 32-bits.  This clearly does bad
things on PAE systems.

This patch fixes this problem by defining these masks as signed quantities.
We then rely on sign extension to do the right thing.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/page.h           |    2 +-
 arch/arm/include/asm/pgtable-3level.h |    6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
index ecf9019..1e0fe08 100644
--- a/arch/arm/include/asm/page.h
+++ b/arch/arm/include/asm/page.h
@@ -13,7 +13,7 @@
 /* PAGE_SHIFT determines the page size */
 #define PAGE_SHIFT		12
 #define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
-#define PAGE_MASK		(~(PAGE_SIZE-1))
+#define PAGE_MASK		(~((1 << PAGE_SHIFT) - 1))
 
 #ifndef __ASSEMBLY__
 
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index b249035..ae39d11 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -48,16 +48,16 @@
 #define PMD_SHIFT		21
 
 #define PMD_SIZE		(1UL << PMD_SHIFT)
-#define PMD_MASK		(~(PMD_SIZE-1))
+#define PMD_MASK		(~((1 << PMD_SHIFT) - 1))
 #define PGDIR_SIZE		(1UL << PGDIR_SHIFT)
-#define PGDIR_MASK		(~(PGDIR_SIZE-1))
+#define PGDIR_MASK		(~((1 << PGDIR_SHIFT) - 1))
 
 /*
  * section address mask and size definitions.
  */
 #define SECTION_SHIFT		21
 #define SECTION_SIZE		(1UL << SECTION_SHIFT)
-#define SECTION_MASK		(~(SECTION_SIZE-1))
+#define SECTION_MASK		(~((1 << SECTION_SHIFT) - 1))
 
 #define USER_PTRS_PER_PGD	(PAGE_OFFSET / PGDIR_SIZE)
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 07/22] ARM: LPAE: use phys_addr_t in alloc_init_pud()
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (5 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 08/22] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
                   ` (14 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Vitaly Andrianov, Cyril Chemparathy

From: Vitaly Andrianov <vitalya@ti.com>

This patch fixes the alloc_init_pud() function to use phys_addr_t instead of
unsigned long when passing in the phys argument.

This is an extension to commit 97092e0c56830457af0639f6bd904537a150ea4a (ARM:
pgtable: use phys_addr_t for physical addresses), which applied similar changes
elsewhere in the ARM memory management code.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/mm/mmu.c |    3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 4c2d045..53eeeb8 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -622,7 +622,8 @@ static void __init alloc_init_section(pud_t *pud, unsigned long addr,
 }
 
 static void __init alloc_init_pud(pgd_t *pgd, unsigned long addr,
-	unsigned long end, unsigned long phys, const struct mem_type *type)
+				  unsigned long end, phys_addr_t phys,
+				  const struct mem_type *type)
 {
 	pud_t *pud = pud_offset(pgd, addr);
 	unsigned long next;
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 08/22] ARM: LPAE: use phys_addr_t in free_memmap()
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (6 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 07/22] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
                   ` (13 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Vitaly Andrianov, Cyril Chemparathy

From: Vitaly Andrianov <vitalya@ti.com>

The free_memmap() was mistakenly using unsigned long type to represent
physical addresses.  This breaks on PAE systems where memory could be placed
above the 32-bit addressible limit.

This patch fixes this function to properly use phys_addr_t instead.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 arch/arm/mm/init.c |    6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 9aec41f..19ba70b 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -457,7 +457,7 @@ static inline void
 free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 {
 	struct page *start_pg, *end_pg;
-	unsigned long pg, pgend;
+	phys_addr_t pg, pgend;
 
 	/*
 	 * Convert start_pfn/end_pfn to a struct page pointer.
@@ -469,8 +469,8 @@ free_memmap(unsigned long start_pfn, unsigned long end_pfn)
 	 * Convert to physical addresses, and
 	 * round start upwards and end downwards.
 	 */
-	pg = (unsigned long)PAGE_ALIGN(__pa(start_pg));
-	pgend = (unsigned long)__pa(end_pg) & PAGE_MASK;
+	pg = PAGE_ALIGN(__pa(start_pg));
+	pgend = __pa(end_pg) & PAGE_MASK;
 
 	/*
 	 * If there are free pages between these,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (7 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 08/22] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  3:58   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
                   ` (12 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Vitaly Andrianov, Cyril Chemparathy

From: Vitaly Andrianov <vitalya@ti.com>

This patch fixes the initrd setup code to use phys_addr_t instead of assuming
32-bit addressing.  Without this we cannot boot on systems where initrd is
located above the 4G physical address limit.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/mm/init.c |   13 +++++++------
 1 file changed, 7 insertions(+), 6 deletions(-)

diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
index 19ba70b..bae9d05 100644
--- a/arch/arm/mm/init.c
+++ b/arch/arm/mm/init.c
@@ -36,12 +36,13 @@
 
 #include "mm.h"
 
-static unsigned long phys_initrd_start __initdata = 0;
+static phys_addr_t phys_initrd_start __initdata = 0;
 static unsigned long phys_initrd_size __initdata = 0;
 
 static int __init early_initrd(char *p)
 {
-	unsigned long start, size;
+	phys_addr_t start;
+	unsigned long size;
 	char *endp;
 
 	start = memparse(p, &endp);
@@ -347,14 +348,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
 #ifdef CONFIG_BLK_DEV_INITRD
 	if (phys_initrd_size &&
 	    !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
-		pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
-		       phys_initrd_start, phys_initrd_size);
+		pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
+		       (u64)phys_initrd_start, phys_initrd_size);
 		phys_initrd_start = phys_initrd_size = 0;
 	}
 	if (phys_initrd_size &&
 	    memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
-		pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
-		       phys_initrd_start, phys_initrd_size);
+		pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
+		       (u64)phys_initrd_start, phys_initrd_size);
 		phys_initrd_start = phys_initrd_size = 0;
 	}
 	if (phys_initrd_size) {
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm()
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (8 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  4:04   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
                   ` (11 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch modifies the switch_mm() processor functions to use phys_addr_t.
On LPAE systems, we now honor the upper 32-bits of the physical address that
is being passed in, and program these into TTBR as expected.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/proc-fns.h |    4 ++--
 arch/arm/mm/proc-v7-3level.S    |   26 ++++++++++++++++++++++----
 2 files changed, 24 insertions(+), 6 deletions(-)

diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index f3628fb..75b5f14 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -60,7 +60,7 @@ extern struct processor {
 	/*
 	 * Set the page table
 	 */
-	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
+	void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
 	/*
 	 * Set a possibly extended PTE.  Non-extended PTEs should
 	 * ignore 'ext'.
@@ -82,7 +82,7 @@ extern void cpu_proc_init(void);
 extern void cpu_proc_fin(void);
 extern int cpu_do_idle(void);
 extern void cpu_dcache_clean_area(void *, int);
-extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
+extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
 #ifdef CONFIG_ARM_LPAE
 extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
 #else
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 8de0f1d..78bd88c 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -39,6 +39,22 @@
 #define TTB_FLAGS_SMP	(TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
 #define PMD_FLAGS_SMP	(PMD_SECT_WBWA|PMD_SECT_S)
 
+#define rzero	r3
+#ifndef CONFIG_ARM_LPAE
+#  define rpgdl	r0
+#  define rpgdh	rzero
+#  define rmm	r1
+#else
+#  define rmm	r2
+#ifndef __ARMEB__
+#  define rpgdl	r0
+#  define rpgdh	r1
+#else
+#  define rpgdl	r1
+#  define rpgdh	r0
+#endif
+#endif
+
 /*
  * cpu_v7_switch_mm(pgd_phys, tsk)
  *
@@ -47,10 +63,12 @@
  */
 ENTRY(cpu_v7_switch_mm)
 #ifdef CONFIG_MMU
-	ldr	r1, [r1, #MM_CONTEXT_ID]	@ get mm->context.id
-	and	r3, r1, #0xff
-	mov	r3, r3, lsl #(48 - 32)		@ ASID
-	mcrr	p15, 0, r0, r3, c2		@ set TTB 0
+	mov	rzero, #0
+	ldr	rmm, [rmm, #MM_CONTEXT_ID]	@ get mm->context.id
+	and	rmm, rmm, #0xff
+	mov	rmm, rmm, lsl #(48 - 32)	@ ASID
+	orr	rpgdh, rpgdh, rmm		@ upper 32-bits of pgd phys
+	mcrr	p15, 0, rpgdl, rpgdh, c2	@ set TTB 0
 	isb
 #endif
 	mov	pc, lr
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (9 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  4:11   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 12/22] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
                   ` (10 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch adds TTBR accessor macros, and modifies cpu_get_pgd() and
the LPAE version of cpu_set_reserved_ttbr0() to use these instead.

In the process, we also fix these functions to correctly handle cases
where the physical address lies beyond the 4G limit of 32-bit addressing.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/proc-fns.h |   24 +++++++++++++++++++-----
 arch/arm/mm/context.c           |    9 ++-------
 2 files changed, 21 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
index 75b5f14..24224df 100644
--- a/arch/arm/include/asm/proc-fns.h
+++ b/arch/arm/include/asm/proc-fns.h
@@ -116,13 +116,27 @@ extern void cpu_resume(void);
 #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
 
 #ifdef CONFIG_ARM_LPAE
+
+#define cpu_get_ttbr(nr)					\
+	({							\
+		u64 ttbr;					\
+		__asm__("mrrc	p15, " #nr ", %Q0, %R0, c2"	\
+			: "=r" (ttbr)				\
+			: : "cc");				\
+		ttbr;						\
+	})
+
+#define cpu_set_ttbr(nr, val)					\
+	do {							\
+		u64 ttbr = val;					\
+		__asm__("mcrr	p15, " #nr ", %Q0, %R0, c2"	\
+			: : "r" (ttbr)				\
+			: "cc");				\
+	} while (0)
+
 #define cpu_get_pgd()	\
 	({						\
-		unsigned long pg, pg2;			\
-		__asm__("mrrc	p15, 0, %0, %1, c2"	\
-			: "=r" (pg), "=r" (pg2)		\
-			:				\
-			: "cc");			\
+		u64 pg = cpu_get_ttbr(0);		\
 		pg &= ~(PTRS_PER_PGD*sizeof(pgd_t)-1);	\
 		(pgd_t *)phys_to_virt(pg);		\
 	})
diff --git a/arch/arm/mm/context.c b/arch/arm/mm/context.c
index 119bc52..cd27f35 100644
--- a/arch/arm/mm/context.c
+++ b/arch/arm/mm/context.c
@@ -16,6 +16,7 @@
 #include <asm/mmu_context.h>
 #include <asm/thread_notify.h>
 #include <asm/tlbflush.h>
+#include <asm/proc-fns.h>
 
 static DEFINE_RAW_SPINLOCK(cpu_asid_lock);
 unsigned int cpu_last_asid = ASID_FIRST_VERSION;
@@ -23,17 +24,11 @@ unsigned int cpu_last_asid = ASID_FIRST_VERSION;
 #ifdef CONFIG_ARM_LPAE
 void cpu_set_reserved_ttbr0(void)
 {
-	unsigned long ttbl = __pa(swapper_pg_dir);
-	unsigned long ttbh = 0;
-
 	/*
 	 * Set TTBR0 to swapper_pg_dir which contains only global entries. The
 	 * ASID is set to 0.
 	 */
-	asm volatile(
-	"	mcrr	p15, 0, %0, %1, c2		@ set TTBR0\n"
-	:
-	: "r" (ttbl), "r" (ttbh));
+	cpu_set_ttbr(0, __pa(swapper_pg_dir));
 	isb();
 }
 #else
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 12/22] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (10 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
                   ` (9 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch adds an architecture defined override for ARCH_LOW_ADDRESS_LIMIT.
On PAE systems, the absence of this override causes bootmem to incorrectly
limit itself to 32-bit addressable physical memory.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/memory.h |    2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index dc5fbf3..64db5a4 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -292,6 +292,8 @@ static inline __deprecated void *bus_to_virt(unsigned long x)
 #define arch_is_coherent()		0
 #endif
 
+#define ARCH_LOW_ADDRESS_LIMIT		PHYS_MASK
+
 #endif
 
 #include <asm-generic/memory_model.h>
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (11 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 12/22] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  4:19   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 14/22] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
                   ` (8 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch moves the TTBR1 offset calculation and the T1SZ calculation out
of the TTB setup assembly code.  This should not affect functionality in
any way, but improves code readability as well as readability of subsequent
patches in this series.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/pgtable-3level-hwdef.h |   10 ++++++++++
 arch/arm/mm/proc-v7-3level.S                |   16 ++++------------
 2 files changed, 14 insertions(+), 12 deletions(-)

diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
index d795282..b501650 100644
--- a/arch/arm/include/asm/pgtable-3level-hwdef.h
+++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
@@ -74,4 +74,14 @@
 #define PHYS_MASK_SHIFT		(40)
 #define PHYS_MASK		((1ULL << PHYS_MASK_SHIFT) - 1)
 
+#if defined CONFIG_VMSPLIT_2G
+#define TTBR1_OFFSET	(1 << 4)		/* skip two L1 entries */
+#elif defined CONFIG_VMSPLIT_3G
+#define TTBR1_OFFSET	(4096 * (1 + 3))	/* only L2, skip pgd + 3*pmd */
+#else
+#define TTBR1_OFFSET	0
+#endif
+
+#define TTBR1_SIZE	(((PAGE_OFFSET >> 30) - 1) << 16)
+
 #endif
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index 78bd88c..e28383f 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -137,18 +137,10 @@ ENDPROC(cpu_v7_set_pte_ext)
 	 * booting secondary CPUs would end up using TTBR1 for the identity
 	 * mapping set up in TTBR0.
 	 */
-	bhi	9001f				@ PHYS_OFFSET > PAGE_OFFSET?
-	orr	\tmp, \tmp, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ
-#if defined CONFIG_VMSPLIT_2G
-	/* PAGE_OFFSET == 0x80000000, T1SZ == 1 */
-	add	\ttbr1, \ttbr1, #1 << 4		@ skip two L1 entries
-#elif defined CONFIG_VMSPLIT_3G
-	/* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
-	add	\ttbr1, \ttbr1, #4096 * (1 + 3)	@ only L2 used, skip pgd+3*pmd
-#endif
-	/* CONFIG_VMSPLIT_1G does not need TTBR1 adjustment */
-9001:	mcr	p15, 0, \tmp, c2, c0, 2		@ TTB control register
-	mcrr	p15, 1, \ttbr1, \zero, c2	@ load TTBR1
+	orrls	\tmp, \tmp, #TTBR1_SIZE				@ TTBCR.T1SZ
+	mcr	p15, 0, \tmp, c2, c0, 2				@ TTBCR
+	addls	\ttbr1, \ttbr1, #TTBR1_OFFSET
+	mcrr	p15, 1, \ttbr1, \zero, c2			@ load TTBR1
 	.endm
 
 	__CPUINIT
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 14/22] ARM: LPAE: accomodate >32-bit addresses for page table base
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (12 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-11  1:24 ` [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
                   ` (7 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch redefines the early boot time use of the R4 register to steal a few
low order bits (ARCH_PGD_SHIFT bits) on LPAE systems.  This allows for up to
38-bit physical addresses.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/memory.h |   15 +++++++++++++++
 arch/arm/kernel/head.S        |   10 ++++------
 arch/arm/kernel/smp.c         |   11 +++++++++--
 arch/arm/mm/proc-v7-3level.S  |    8 ++++++++
 4 files changed, 36 insertions(+), 8 deletions(-)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 64db5a4..e5d0cc8 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -18,6 +18,7 @@
 #include <linux/types.h>
 #include <linux/sizes.h>
 
+#include <asm/cache.h>
 #include <asm/runtime-patch.h>
 
 #ifdef CONFIG_NEED_MACH_MEMORY_H
@@ -143,6 +144,20 @@
 #define page_to_phys(page)	(__pfn_to_phys(page_to_pfn(page)))
 #define phys_to_page(phys)	(pfn_to_page(__phys_to_pfn(phys)))
 
+/*
+ * Minimum guaranted alignment in pgd_alloc().  The page table pointers passed
+ * around in head.S and proc-*.S are shifted by this amount, in order to
+ * leave spare high bits for systems with physical address extension.  This
+ * does not fully accomodate the 40-bit addressing capability of ARM LPAE, but
+ * gives us about 38-bits or so.
+ */
+#ifdef CONFIG_ARM_LPAE
+#define ARCH_PGD_SHIFT		L1_CACHE_SHIFT
+#else
+#define ARCH_PGD_SHIFT		0
+#endif
+#define ARCH_PGD_MASK		((1 << ARCH_PGD_SHIFT) - 1)
+
 #ifndef __ASSEMBLY__
 
 /*
diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
index 61fb8df..9664db0 100644
--- a/arch/arm/kernel/head.S
+++ b/arch/arm/kernel/head.S
@@ -152,7 +152,7 @@ ENDPROC(stext)
  *
  * Returns:
  *  r0, r3, r5-r7 corrupted
- *  r4 = physical page table address
+ *  r4 = page table (see ARCH_PGD_SHIFT in asm/memory.h)
  */
 __create_page_tables:
 	pgtbl	r4, r8				@ page table address
@@ -306,6 +306,7 @@ __create_page_tables:
 #endif
 #ifdef CONFIG_ARM_LPAE
 	sub	r4, r4, #0x1000		@ point to the PGD table
+	mov	r4, r4, lsr #ARCH_PGD_SHIFT
 #endif
 	mov	pc, lr
 ENDPROC(__create_page_tables)
@@ -379,7 +380,7 @@ __secondary_data:
  *  r0  = cp#15 control register
  *  r1  = machine ID
  *  r2  = atags or dtb pointer
- *  r4  = page table pointer
+ *  r4  = page table (see ARCH_PGD_SHIFT in asm/memory.h)
  *  r9  = processor ID
  *  r13 = *virtual* address to jump to upon completion
  */
@@ -398,10 +399,7 @@ __enable_mmu:
 #ifdef CONFIG_CPU_ICACHE_DISABLE
 	bic	r0, r0, #CR_I
 #endif
-#ifdef CONFIG_ARM_LPAE
-	mov	r5, #0
-	mcrr	p15, 0, r4, r5, c2		@ load TTBR0
-#else
+#ifndef CONFIG_ARM_LPAE
 	mov	r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
 		      domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
 		      domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index ebd8ad2..9831716 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -60,6 +60,13 @@ enum ipi_msg_type {
 
 static DECLARE_COMPLETION(cpu_running);
 
+static unsigned long get_arch_pgd(pgd_t *pgd)
+{
+	phys_addr_t pgdir = virt_to_phys(pgd);
+	BUG_ON(pgdir & ARCH_PGD_MASK);
+	return pgdir >> ARCH_PGD_SHIFT;
+}
+
 int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
 {
 	int ret;
@@ -69,8 +76,8 @@ int __cpuinit __cpu_up(unsigned int cpu, struct task_struct *idle)
 	 * its stack and the page tables.
 	 */
 	secondary_data.stack = task_stack_page(idle) + THREAD_START_SP;
-	secondary_data.pgdir = virt_to_phys(idmap_pgd);
-	secondary_data.swapper_pg_dir = virt_to_phys(swapper_pg_dir);
+	secondary_data.pgdir = get_arch_pgd(idmap_pgd);
+	secondary_data.swapper_pg_dir = get_arch_pgd(swapper_pg_dir);
 	__cpuc_flush_dcache_area(&secondary_data, sizeof(secondary_data));
 	outer_clean_range(__pa(&secondary_data), __pa(&secondary_data + 1));
 
diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
index e28383f..6fa0444 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -120,6 +120,7 @@ ENDPROC(cpu_v7_set_pte_ext)
 	 */
 	.macro	v7_ttb_setup, zero, ttbr0, ttbr1, tmp
 	ldr	\tmp, =swapper_pg_dir		@ swapper_pg_dir virtual address
+	mov	\tmp, \tmp, lsr #ARCH_PGD_SHIFT
 	cmp	\ttbr1, \tmp			@ PHYS_OFFSET > PAGE_OFFSET? (branch below)
 	mrc	p15, 0, \tmp, c2, c0, 2		@ TTB control register
 	orr	\tmp, \tmp, #TTB_EAE
@@ -139,8 +140,15 @@ ENDPROC(cpu_v7_set_pte_ext)
 	 */
 	orrls	\tmp, \tmp, #TTBR1_SIZE				@ TTBCR.T1SZ
 	mcr	p15, 0, \tmp, c2, c0, 2				@ TTBCR
+	mov	\tmp, \ttbr1, lsr #(32 - ARCH_PGD_SHIFT)	@ upper bits
+	mov	\ttbr1, \ttbr1, lsl #ARCH_PGD_SHIFT		@ lower bits
 	addls	\ttbr1, \ttbr1, #TTBR1_OFFSET
 	mcrr	p15, 1, \ttbr1, \zero, c2			@ load TTBR1
+	mov	\tmp, \ttbr0, lsr #(32 - ARCH_PGD_SHIFT)	@ upper bits
+	mov	\ttbr0, \ttbr0, lsl #ARCH_PGD_SHIFT		@ lower bits
+	mcrr	p15, 0, \ttbr0, \zero, c2			@ load TTBR0
+	mcrr	p15, 1, \ttbr1, \zero, c2			@ load TTBR1
+	mcrr	p15, 0, \ttbr0, \zero, c2			@ load TTBR0
 	.endm
 
 	__CPUINIT
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (13 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 14/22] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  4:29   ` Nicolas Pitre
  2012-08-11  1:24 ` [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
                   ` (6 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch modifies the highmem sanity checking code to use physical addresses
instead.  This change eliminates the wrap-around problems associated with the
original virtual address based checks, and this simplifies the code a bit.

The one constraint imposed here is that low physical memory must be mapped in
a monotonically increasing fashion if there are multiple banks of memory,
i.e., x < y must => pa(x) < pa(y).

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/mm/mmu.c |   22 ++++++++++------------
 1 file changed, 10 insertions(+), 12 deletions(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 53eeeb8..f764c03 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -895,6 +895,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
 void __init sanity_check_meminfo(void)
 {
 	int i, j, highmem = 0;
+	phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
 
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
@@ -904,8 +905,7 @@ void __init sanity_check_meminfo(void)
 			highmem = 1;
 
 #ifdef CONFIG_HIGHMEM
-		if (__va(bank->start) >= vmalloc_min ||
-		    __va(bank->start) < (void *)PAGE_OFFSET)
+		if (bank->start >= vmalloc_limit)
 			highmem = 1;
 
 		bank->highmem = highmem;
@@ -914,8 +914,8 @@ void __init sanity_check_meminfo(void)
 		 * Split those memory banks which are partially overlapping
 		 * the vmalloc area greatly simplifying things later.
 		 */
-		if (!highmem && __va(bank->start) < vmalloc_min &&
-		    bank->size > vmalloc_min - __va(bank->start)) {
+		if (!highmem && bank->start < vmalloc_limit &&
+		    bank->size > vmalloc_limit - bank->start) {
 			if (meminfo.nr_banks >= NR_BANKS) {
 				printk(KERN_CRIT "NR_BANKS too low, "
 						 "ignoring high memory\n");
@@ -924,12 +924,12 @@ void __init sanity_check_meminfo(void)
 					(meminfo.nr_banks - i) * sizeof(*bank));
 				meminfo.nr_banks++;
 				i++;
-				bank[1].size -= vmalloc_min - __va(bank->start);
-				bank[1].start = __pa(vmalloc_min - 1) + 1;
+				bank[1].size -= vmalloc_limit - bank->start;
+				bank[1].start = vmalloc_limit;
 				bank[1].highmem = highmem = 1;
 				j++;
 			}
-			bank->size = vmalloc_min - __va(bank->start);
+			bank->size = vmalloc_limit - bank->start;
 		}
 #else
 		bank->highmem = highmem;
@@ -949,8 +949,7 @@ void __init sanity_check_meminfo(void)
 		 * Check whether this memory bank would entirely overlap
 		 * the vmalloc area.
 		 */
-		if (__va(bank->start) >= vmalloc_min ||
-		    __va(bank->start) < (void *)PAGE_OFFSET) {
+		if (bank->start >= vmalloc_limit) {
 			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
 			       "(vmalloc region overlap).\n",
 			       (unsigned long long)bank->start,
@@ -962,9 +961,8 @@ void __init sanity_check_meminfo(void)
 		 * Check whether this memory bank would partially overlap
 		 * the vmalloc area.
 		 */
-		if (__va(bank->start + bank->size) > vmalloc_min ||
-		    __va(bank->start + bank->size) < __va(bank->start)) {
-			unsigned long newsize = vmalloc_min - __va(bank->start);
+		if (bank->start + bank->size > vmalloc_limit)
+			unsigned long newsize = vmalloc_limit - bank->start;
 			printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
 			       "to -%.8llx (vmalloc region overlap).\n",
 			       (unsigned long long)bank->start,
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (14 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
@ 2012-08-11  1:24 ` Cyril Chemparathy
  2012-08-12  4:36   ` Nicolas Pitre
  2012-08-11  1:25 ` [PATCH v2 17/22] ARM: mm: clean up membank size limit checks Cyril Chemparathy
                   ` (5 subsequent siblings)
  21 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:24 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

On Keystone platforms, physical memory is entirely outside the 32-bit
addressible range.  Therefore, the (bank->start > ULONG_MAX) check below marks
the entire system memory as highmem, and this causes unpleasentness all over.

This patch eliminates the extra bank start check (against ULONG_MAX) by
checking bank->start against the physical address corresponding to vmalloc_min
instead.

In the process, this patch also cleans up parts of the highmem sanity check
code by removing what has now become a redundant check for banks that entirely
overlap with the vmalloc range.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/mm/mmu.c |   19 +------------------
 1 file changed, 1 insertion(+), 18 deletions(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index f764c03..3d685c6 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -901,15 +901,12 @@ void __init sanity_check_meminfo(void)
 		struct membank *bank = &meminfo.bank[j];
 		*bank = meminfo.bank[i];
 
-		if (bank->start > ULONG_MAX)
-			highmem = 1;
-
-#ifdef CONFIG_HIGHMEM
 		if (bank->start >= vmalloc_limit)
 			highmem = 1;
 
 		bank->highmem = highmem;
 
+#ifdef CONFIG_HIGHMEM
 		/*
 		 * Split those memory banks which are partially overlapping
 		 * the vmalloc area greatly simplifying things later.
@@ -932,8 +929,6 @@ void __init sanity_check_meminfo(void)
 			bank->size = vmalloc_limit - bank->start;
 		}
 #else
-		bank->highmem = highmem;
-
 		/*
 		 * Highmem banks not allowed with !CONFIG_HIGHMEM.
 		 */
@@ -946,18 +941,6 @@ void __init sanity_check_meminfo(void)
 		}
 
 		/*
-		 * Check whether this memory bank would entirely overlap
-		 * the vmalloc area.
-		 */
-		if (bank->start >= vmalloc_limit) {
-			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
-			       "(vmalloc region overlap).\n",
-			       (unsigned long long)bank->start,
-			       (unsigned long long)bank->start + bank->size - 1);
-			continue;
-		}
-
-		/*
 		 * Check whether this memory bank would partially overlap
 		 * the vmalloc area.
 		 */
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 17/22] ARM: mm: clean up membank size limit checks
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (15 preceding siblings ...)
  2012-08-11  1:24 ` [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  2012-08-11  1:25 ` [PATCH v2 18/22] ARM: add virt_to_idmap for interconnect aliasing Cyril Chemparathy
                   ` (4 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch cleans up the highmem sanity check code by simplifying the range
checks with a pre-calculated size_limit.  This patch should otherwise have no
functional impact on behavior.

This patch also removes a redundant (bank->start < vmalloc_limit) check, since
this is already covered by the !highmem condition.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/mm/mmu.c |   19 +++++++++++--------
 1 file changed, 11 insertions(+), 8 deletions(-)

diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 3d685c6..662684b 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -899,10 +899,15 @@ void __init sanity_check_meminfo(void)
 
 	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
 		struct membank *bank = &meminfo.bank[j];
+		phys_addr_t size_limit;
+
 		*bank = meminfo.bank[i];
+		size_limit = bank->size;
 
 		if (bank->start >= vmalloc_limit)
 			highmem = 1;
+		else
+			size_limit = vmalloc_limit - bank->start;
 
 		bank->highmem = highmem;
 
@@ -911,8 +916,7 @@ void __init sanity_check_meminfo(void)
 		 * Split those memory banks which are partially overlapping
 		 * the vmalloc area greatly simplifying things later.
 		 */
-		if (!highmem && bank->start < vmalloc_limit &&
-		    bank->size > vmalloc_limit - bank->start) {
+		if (!highmem && bank->size > size_limit) {
 			if (meminfo.nr_banks >= NR_BANKS) {
 				printk(KERN_CRIT "NR_BANKS too low, "
 						 "ignoring high memory\n");
@@ -921,12 +925,12 @@ void __init sanity_check_meminfo(void)
 					(meminfo.nr_banks - i) * sizeof(*bank));
 				meminfo.nr_banks++;
 				i++;
-				bank[1].size -= vmalloc_limit - bank->start;
+				bank[1].size -= size_limit;
 				bank[1].start = vmalloc_limit;
 				bank[1].highmem = highmem = 1;
 				j++;
 			}
-			bank->size = vmalloc_limit - bank->start;
+			bank->size = size_limit;
 		}
 #else
 		/*
@@ -944,14 +948,13 @@ void __init sanity_check_meminfo(void)
 		 * Check whether this memory bank would partially overlap
 		 * the vmalloc area.
 		 */
-		if (bank->start + bank->size > vmalloc_limit)
-			unsigned long newsize = vmalloc_limit - bank->start;
+		if (bank->size > size_limit) {
 			printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
 			       "to -%.8llx (vmalloc region overlap).\n",
 			       (unsigned long long)bank->start,
 			       (unsigned long long)bank->start + bank->size - 1,
-			       (unsigned long long)bank->start + newsize - 1);
-			bank->size = newsize;
+			       (unsigned long long)bank->start + size_limit - 1);
+			bank->size = size_limit;
 		}
 #endif
 		if (!bank->highmem && bank->start + bank->size > arm_lowmem_limit)
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 18/22] ARM: add virt_to_idmap for interconnect aliasing
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (16 preceding siblings ...)
  2012-08-11  1:25 ` [PATCH v2 17/22] ARM: mm: clean up membank size limit checks Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  2012-08-11  1:25 ` [PATCH v2 19/22] ARM: recreate kernel mappings in early_paging_init() Cyril Chemparathy
                   ` (3 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Vitaly Andrianov, Cyril Chemparathy

From: Vitaly Andrianov <vitalya@ti.com>

On some PAE systems (e.g. TI Keystone), memory is above the 32-bit addressible
limit, and the interconnect provides an aliased view of parts of physical
memory in the 32-bit addressible space.  This alias is strictly for boot time
usage, and is not otherwise usable because of coherency limitations.

On such systems, the idmap mechanism needs to take this aliased mapping into
account.  This patch introduces a virt_to_idmap() macro, which can be used on
such sub-architectures to represent the interconnect supported boot time
alias.  Most other systems would leave this macro untouched, i.e., do a simply
virt_to_phys() and nothing more.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/include/asm/memory.h |    9 +++++++++
 arch/arm/kernel/smp.c         |    2 +-
 arch/arm/mm/idmap.c           |    4 ++--
 3 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index e5d0cc8..59f101c 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -257,6 +257,15 @@ static inline void *phys_to_virt(phys_addr_t x)
 #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
 
 /*
+ * These are for systems that have a hardware interconnect supported alias of
+ * physical memory for idmap purposes.  Most cases should leave these
+ * untouched.
+ */
+#ifndef virt_to_idmap
+#define virt_to_idmap(x) virt_to_phys(x)
+#endif
+
+/*
  * Virtual <-> DMA view memory address translations
  * Again, these are *only* valid on the kernel direct mapped RAM
  * memory.  Use of these is *deprecated* (and that doesn't mean
diff --git a/arch/arm/kernel/smp.c b/arch/arm/kernel/smp.c
index 9831716..628f895 100644
--- a/arch/arm/kernel/smp.c
+++ b/arch/arm/kernel/smp.c
@@ -62,7 +62,7 @@ static DECLARE_COMPLETION(cpu_running);
 
 static unsigned long get_arch_pgd(pgd_t *pgd)
 {
-	phys_addr_t pgdir = virt_to_phys(pgd);
+	phys_addr_t pgdir = virt_to_idmap(pgd);
 	BUG_ON(pgdir & ARCH_PGD_MASK);
 	return pgdir >> ARCH_PGD_SHIFT;
 }
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index ab88ed4..919cb6e 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -85,8 +85,8 @@ static int __init init_static_idmap(void)
 		return -ENOMEM;
 
 	/* Add an identity mapping for the physical address of the section. */
-	idmap_start = virt_to_phys((void *)__idmap_text_start);
-	idmap_end = virt_to_phys((void *)__idmap_text_end);
+	idmap_start = virt_to_idmap((void *)__idmap_text_start);
+	idmap_end = virt_to_idmap((void *)__idmap_text_end);
 
 	pr_info("Setting up static identity map for 0x%llx - 0x%llx\n",
 		(long long)idmap_start, (long long)idmap_end);
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [PATCH v2 19/22] ARM: recreate kernel mappings in early_paging_init()
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (17 preceding siblings ...)
  2012-08-11  1:25 ` [PATCH v2 18/22] ARM: add virt_to_idmap for interconnect aliasing Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  2012-08-11  1:25 ` [RFC v2 20/22] ARM: keystone: introducing TI Keystone platform Cyril Chemparathy
                   ` (2 subsequent siblings)
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch adds a step in the init sequence, in order to recreate the kernel
code/data page table mappings prior to full paging initialization.  This is
necessary on LPAE systems that run out of a physical address space outside the
4G limit.  On these systems, this implementation provides a machine descriptor
hook that allows the PHYS_OFFSET to be overridden in a machine specific
fashion.

Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
---
 arch/arm/include/asm/mach/arch.h |    1 +
 arch/arm/kernel/setup.c          |    3 ++
 arch/arm/mm/mmu.c                |   65 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 69 insertions(+)

diff --git a/arch/arm/include/asm/mach/arch.h b/arch/arm/include/asm/mach/arch.h
index 0b1c94b..2b9ecc5 100644
--- a/arch/arm/include/asm/mach/arch.h
+++ b/arch/arm/include/asm/mach/arch.h
@@ -37,6 +37,7 @@ struct machine_desc {
 	char			restart_mode;	/* default restart mode	*/
 	void			(*fixup)(struct tag *, char **,
 					 struct meminfo *);
+	void			(*init_meminfo)(void);
 	void			(*reserve)(void);/* reserve mem blocks	*/
 	void			(*map_io)(void);/* IO mapping function	*/
 	void			(*init_early)(void);
diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
index edb4f42..e37cbaf 100644
--- a/arch/arm/kernel/setup.c
+++ b/arch/arm/kernel/setup.c
@@ -79,6 +79,7 @@ static int __init fpe_setup(char *line)
 __setup("fpe=", fpe_setup);
 #endif
 
+extern void early_paging_init(struct machine_desc *, struct proc_info_list *);
 extern void paging_init(struct machine_desc *desc);
 extern void sanity_check_meminfo(void);
 extern void reboot_setup(char *str);
@@ -978,6 +979,8 @@ void __init setup_arch(char **cmdline_p)
 	parse_early_param();
 
 	sort(&meminfo.bank, meminfo.nr_banks, sizeof(meminfo.bank[0]), meminfo_cmp, NULL);
+
+	early_paging_init(mdesc, lookup_processor_type(read_cpuid_id()));
 	sanity_check_meminfo();
 	arm_memblock_init(&meminfo, mdesc);
 
diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
index 662684b..5d240da 100644
--- a/arch/arm/mm/mmu.c
+++ b/arch/arm/mm/mmu.c
@@ -28,6 +28,7 @@
 #include <asm/highmem.h>
 #include <asm/system_info.h>
 #include <asm/traps.h>
+#include <asm/procinfo.h>
 
 #include <asm/mach/arch.h>
 #include <asm/mach/map.h>
@@ -1168,6 +1169,70 @@ static void __init map_lowmem(void)
 	}
 }
 
+#ifdef CONFIG_ARM_LPAE
+/*
+ * early_paging_init() recreates boot time page table setup, allowing machines
+ * to switch over to a high (>4G) address space on LPAE systems
+ */
+void __init early_paging_init(struct machine_desc *mdesc,
+			      struct proc_info_list *procinfo)
+{
+	pmdval_t pmdprot = procinfo->__cpu_mm_mmu_flags;
+	unsigned long map_start, map_end;
+	pgd_t *pgd0, *pgdk;
+	pud_t *pud0, *pudk;
+	pmd_t *pmd0, *pmdk;
+	phys_addr_t phys;
+	int i;
+
+	/* remap kernel code and data */
+	map_start = init_mm.start_code;
+	map_end   = init_mm.brk;
+
+	/* get a handle on things... */
+	pgd0 = pgd_offset_k(0);
+	pud0 = pud_offset(pgd0, 0);
+	pmd0 = pmd_offset(pud0, 0);
+
+	pgdk = pgd_offset_k(map_start);
+	pudk = pud_offset(pgdk, map_start);
+	pmdk = pmd_offset(pudk, map_start);
+
+	phys = PHYS_OFFSET;
+
+	if (mdesc->init_meminfo)
+		mdesc->init_meminfo();
+
+	/* remap level 1 table */
+	for (i = 0; i < PTRS_PER_PGD; i++) {
+		*pud0++ = __pud(__pa(pmd0) | PMD_TYPE_TABLE | L_PGD_SWAPPER);
+		pmd0 += PTRS_PER_PMD;
+	}
+
+	/* remap pmds for kernel mapping */
+	phys = __pa(map_start) & PMD_MASK;
+	do {
+		*pmdk++ = __pmd(phys | pmdprot);
+		phys += PMD_SIZE;
+	} while (phys < map_end);
+
+	flush_cache_all();
+	cpu_set_ttbr(0, __pa(pgd0));
+	cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
+	local_flush_tlb_all();
+}
+
+#else
+
+void __init early_paging_init(struct machine_desc *mdesc,
+			      struct proc_info_list *procinfo)
+{
+	if (mdesc->init_meminfo)
+		mdesc->init_meminfo();
+}
+
+#endif
+
 /*
  * paging_init() sets up the page tables, initialises the zone memory
  * maps, and sets up the zero page, bad page and bad page tables.
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [RFC v2 20/22] ARM: keystone: introducing TI Keystone platform
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (18 preceding siblings ...)
  2012-08-11  1:25 ` [PATCH v2 19/22] ARM: recreate kernel mappings in early_paging_init() Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  2012-08-11  1:25 ` [RFC v2 21/22] ARM: keystone: enable SMP on Keystone machines Cyril Chemparathy
  2012-08-11  1:25 ` [RFC v2 22/22] ARM: keystone: add switch over to high physical address range Cyril Chemparathy
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

Texas Instruments Keystone family of multicore devices now includes an
upcoming slew of Cortex A15 based devices.  This patch adds basic definitions
for a new Keystone sub-architecture in ARM.

Subsequent patches in this series will extend support to include SMP and take
advantage of the large physical memory addressing capabilities via LPAE.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
Reviewed-by: Arnd Bergmann <arnd@arndb.de>
---
 arch/arm/Kconfig                                  |   18 +++++
 arch/arm/Makefile                                 |    1 +
 arch/arm/boot/dts/keystone-sim.dts                |   77 +++++++++++++++++++
 arch/arm/configs/keystone_defconfig               |   20 +++++
 arch/arm/mach-keystone/Makefile                   |    1 +
 arch/arm/mach-keystone/Makefile.boot              |    1 +
 arch/arm/mach-keystone/include/mach/debug-macro.S |   44 +++++++++++
 arch/arm/mach-keystone/include/mach/memory.h      |   22 ++++++
 arch/arm/mach-keystone/include/mach/timex.h       |   21 ++++++
 arch/arm/mach-keystone/include/mach/uncompress.h  |   24 ++++++
 arch/arm/mach-keystone/keystone.c                 |   82 +++++++++++++++++++++
 11 files changed, 311 insertions(+)
 create mode 100644 arch/arm/boot/dts/keystone-sim.dts
 create mode 100644 arch/arm/configs/keystone_defconfig
 create mode 100644 arch/arm/mach-keystone/Makefile
 create mode 100644 arch/arm/mach-keystone/Makefile.boot
 create mode 100644 arch/arm/mach-keystone/include/mach/debug-macro.S
 create mode 100644 arch/arm/mach-keystone/include/mach/memory.h
 create mode 100644 arch/arm/mach-keystone/include/mach/timex.h
 create mode 100644 arch/arm/mach-keystone/include/mach/uncompress.h
 create mode 100644 arch/arm/mach-keystone/keystone.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 9ac86ea..f1b8aa0 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -402,6 +402,24 @@ config ARCH_HIGHBANK
 	help
 	  Support for the Calxeda Highbank SoC based boards.
 
+config ARCH_KEYSTONE
+	bool "Texas Instruments Keystone Devices"
+	select ARCH_WANT_OPTIONAL_GPIOLIB
+	select ARM_GIC
+	select MULTI_IRQ_HANDLER
+	select CLKDEV_LOOKUP
+	select COMMON_CLK
+	select CLKSRC_MMIO
+	select CPU_V7
+	select GENERIC_CLOCKEVENTS
+	select USE_OF
+	select SPARSE_IRQ
+	select NEED_MACH_MEMORY_H
+	select HAVE_SCHED_CLOCK
+	help
+	  Support for boards based on the Texas Instruments Keystone family of
+	  SoCs.
+
 config ARCH_CLPS711X
 	bool "Cirrus Logic CLPS711x/EP721x/EP731x-based"
 	select CPU_ARM720T
diff --git a/arch/arm/Makefile b/arch/arm/Makefile
index 30eae87..75b5b79 100644
--- a/arch/arm/Makefile
+++ b/arch/arm/Makefile
@@ -146,6 +146,7 @@ machine-$(CONFIG_ARCH_EP93XX)		:= ep93xx
 machine-$(CONFIG_ARCH_GEMINI)		:= gemini
 machine-$(CONFIG_ARCH_H720X)		:= h720x
 machine-$(CONFIG_ARCH_HIGHBANK)		:= highbank
+machine-$(CONFIG_ARCH_KEYSTONE)		:= keystone
 machine-$(CONFIG_ARCH_INTEGRATOR)	:= integrator
 machine-$(CONFIG_ARCH_IOP13XX)		:= iop13xx
 machine-$(CONFIG_ARCH_IOP32X)		:= iop32x
diff --git a/arch/arm/boot/dts/keystone-sim.dts b/arch/arm/boot/dts/keystone-sim.dts
new file mode 100644
index 0000000..acec30f8
--- /dev/null
+++ b/arch/arm/boot/dts/keystone-sim.dts
@@ -0,0 +1,77 @@
+/dts-v1/;
+/include/ "skeleton.dtsi"
+
+/ {
+	model = "Texas Instruments Keystone 2 SoC";
+	compatible = "ti,keystone-evm";
+	#address-cells = <1>;
+	#size-cells = <1>;
+	interrupt-parent = <&gic>;
+
+	aliases {
+		serial0	= &uart0;
+	};
+
+	chosen {
+		bootargs = "console=ttyS0,115200n8 debug earlyprintk lpj=50000 rdinit=/bin/ash rw root=/dev/ram0 initrd=0x85000000,2M";
+	};
+
+	memory {
+		reg = <0x80000000 0x8000000>;
+	};
+
+	cpus {
+		interrupt-parent = <&gic>;
+
+		cpu@0 {
+			compatible = "arm,cortex-a15";
+		};
+
+		cpu@1 {
+			compatible = "arm,cortex-a15";
+		};
+
+		cpu@2 {
+			compatible = "arm,cortex-a15";
+		};
+
+		cpu@3 {
+			compatible = "arm,cortex-a15";
+		};
+
+	};
+
+	soc {
+		#address-cells = <1>;
+		#size-cells = <1>;
+		ranges;
+		compatible = "ti,keystone","simple-bus";
+		interrupt-parent = <&gic>;
+
+		gic:	interrupt-controller@02560000 {
+			compatible = "arm,cortex-a15-gic";
+			#interrupt-cells = <3>;
+			#size-cells = <0>;
+			#address-cells = <1>;
+			interrupt-controller;
+			reg = <0x02561000 0x1000>,
+			      <0x02562000 0x2000>;
+		};
+
+		timer {
+			compatible = "arm,armv7-timer";
+			interrupts = <1 13 0xf08 1 14 0xf08>;
+			clock-frequency = <10000000>; /* Freq in Hz - optional */
+		};
+
+		uart0:	serial@02530c00 {
+			compatible	= "ns16550a";
+			current-speed	= <115200>;
+			reg-shift	= <2>;
+			reg-io-width	= <4>;
+			reg		= <0x02530c00 0x100>;
+			clock-frequency = <48000000>;
+			interrupts	= <0 277 0xf01>;
+		};
+	};
+};
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
new file mode 100644
index 0000000..7f2a04b
--- /dev/null
+++ b/arch/arm/configs/keystone_defconfig
@@ -0,0 +1,20 @@
+CONFIG_EXPERIMENTAL=y
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_ARCH_KEYSTONE=y
+CONFIG_ARM_ARCH_TIMER=y
+CONFIG_AEABI=y
+CONFIG_HIGHMEM=y
+CONFIG_VFP=y
+CONFIG_NEON=y
+# CONFIG_SUSPEND is not set
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_BLK_DEV_RAM=y
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_OF_PLATFORM=y
+CONFIG_PRINTK_TIME=y
+CONFIG_DEBUG_KERNEL=y
+CONFIG_DEBUG_INFO=y
+CONFIG_DEBUG_USER=y
+CONFIG_DEBUG_LL=y
+CONFIG_EARLY_PRINTK=y
diff --git a/arch/arm/mach-keystone/Makefile b/arch/arm/mach-keystone/Makefile
new file mode 100644
index 0000000..d4671d5
--- /dev/null
+++ b/arch/arm/mach-keystone/Makefile
@@ -0,0 +1 @@
+obj-y					:= keystone.o
diff --git a/arch/arm/mach-keystone/Makefile.boot b/arch/arm/mach-keystone/Makefile.boot
new file mode 100644
index 0000000..dae9661
--- /dev/null
+++ b/arch/arm/mach-keystone/Makefile.boot
@@ -0,0 +1 @@
+zreladdr-y	:= 0x00008000
diff --git a/arch/arm/mach-keystone/include/mach/debug-macro.S b/arch/arm/mach-keystone/include/mach/debug-macro.S
new file mode 100644
index 0000000..1108210
--- /dev/null
+++ b/arch/arm/mach-keystone/include/mach/debug-macro.S
@@ -0,0 +1,44 @@
+/*
+ * Debugging macro include header
+ *
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ * Copyright (C) 1994-1999 Russell King
+ * Moved from linux/arch/arm/kernel/debug.S by Ben Dooks
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/serial_reg.h>
+
+#define UART_SHIFT	2
+
+	.macro	addruart,rp,rv,tmp
+	movw	\rv, #0x0c00
+	movt	\rv, #0xfed3
+	movw	\rp, #0x0c00
+	movt	\rp, #0x0253
+	.endm
+
+
+	.macro	senduart,rd,rx
+	str	\rd, [\rx, #UART_TX << UART_SHIFT]
+	.endm
+
+	.macro	busyuart,rd,rx
+1002:	ldr	\rd, [\rx, #UART_LSR << UART_SHIFT]
+	and	\rd, \rd, #UART_LSR_TEMT | UART_LSR_THRE
+	teq	\rd, #UART_LSR_TEMT | UART_LSR_THRE
+	bne	1002b
+	.endm
+
+	.macro	waituart,rd,rx
+	.endm
diff --git a/arch/arm/mach-keystone/include/mach/memory.h b/arch/arm/mach-keystone/include/mach/memory.h
new file mode 100644
index 0000000..7c78b1e
--- /dev/null
+++ b/arch/arm/mach-keystone/include/mach/memory.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __ASM_MACH_MEMORY_H
+#define __ASM_MACH_MEMORY_H
+
+#define MAX_PHYSMEM_BITS	36
+#define SECTION_SIZE_BITS	34
+
+#endif /* __ASM_MACH_MEMORY_H */
diff --git a/arch/arm/mach-keystone/include/mach/timex.h b/arch/arm/mach-keystone/include/mach/timex.h
new file mode 100644
index 0000000..f355ecb
--- /dev/null
+++ b/arch/arm/mach-keystone/include/mach/timex.h
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __MACH_TIMEX_H
+#define __MACH_TIMEX_H
+
+#define CLOCK_TICK_RATE		1000000
+
+#endif
diff --git a/arch/arm/mach-keystone/include/mach/uncompress.h b/arch/arm/mach-keystone/include/mach/uncompress.h
new file mode 100644
index 0000000..1071761
--- /dev/null
+++ b/arch/arm/mach-keystone/include/mach/uncompress.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#ifndef __MACH_UNCOMPRESS_H
+#define __MACH_UNCOMPRESS_H
+
+#define putc(c)
+#define flush()
+#define arch_decomp_setup()
+#define arch_decomp_wdog()
+
+#endif
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
new file mode 100644
index 0000000..702c184
--- /dev/null
+++ b/arch/arm/mach-keystone/keystone.c
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/io.h>
+#include <linux/of.h>
+#include <linux/init.h>
+#include <linux/of_irq.h>
+#include <linux/of_platform.h>
+
+#include <asm/setup.h>
+#include <asm/mach/map.h>
+#include <asm/mach/arch.h>
+#include <asm/mach/time.h>
+#include <asm/arch_timer.h>
+#include <asm/hardware/gic.h>
+
+static struct map_desc io_desc[] = {
+	{
+		.virtual        = 0xfe800000UL,
+		.pfn            = __phys_to_pfn(0x02000000UL),
+		.length         = 0x800000UL,
+		.type           = MT_DEVICE
+	},
+};
+
+static void __init keystone_map_io(void)
+{
+	iotable_init(io_desc, ARRAY_SIZE(io_desc));
+}
+
+static const struct of_device_id irq_match[] = {
+	{ .compatible = "arm,cortex-a15-gic", .data = gic_of_init, },
+	{}
+};
+
+static void __init keystone_init_irq(void)
+{
+	of_irq_init(irq_match);
+}
+
+
+static void __init keystone_timer_init(void)
+{
+	arch_timer_of_register();
+	arch_timer_sched_clock_init();
+}
+
+static struct sys_timer keystone_timer = {
+	.init = keystone_timer_init,
+};
+
+
+static void __init keystone_init(void)
+{
+	of_platform_populate(NULL, of_default_bus_match_table, NULL, NULL);
+}
+
+static const char *keystone_match[] __initconst = {
+	"ti,keystone-evm",
+	NULL,
+};
+
+DT_MACHINE_START(KEYSTONE, "Keystone")
+	.map_io		= keystone_map_io,
+	.init_irq	= keystone_init_irq,
+	.timer		= &keystone_timer,
+	.handle_irq	= gic_handle_irq,
+	.init_machine	= keystone_init,
+	.dt_compat	= keystone_match,
+MACHINE_END
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [RFC v2 21/22] ARM: keystone: enable SMP on Keystone machines
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (19 preceding siblings ...)
  2012-08-11  1:25 ` [RFC v2 20/22] ARM: keystone: introducing TI Keystone platform Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  2012-08-11  1:25 ` [RFC v2 22/22] ARM: keystone: add switch over to high physical address range Cyril Chemparathy
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

This patch adds basic SMP support for Keystone machines.  Nothing very fancy
here, just enough to get 4 CPUs booted up.  This does not include support for
hotplug, etc.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/Kconfig                    |    1 +
 arch/arm/configs/keystone_defconfig |    2 +
 arch/arm/mach-keystone/Makefile     |    1 +
 arch/arm/mach-keystone/keystone.c   |    3 ++
 arch/arm/mach-keystone/keystone.h   |   23 +++++++++++
 arch/arm/mach-keystone/platsmp.c    |   74 +++++++++++++++++++++++++++++++++++
 6 files changed, 104 insertions(+)
 create mode 100644 arch/arm/mach-keystone/keystone.h
 create mode 100644 arch/arm/mach-keystone/platsmp.c

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index f1b8aa0..37b4e9c 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -416,6 +416,7 @@ config ARCH_KEYSTONE
 	select SPARSE_IRQ
 	select NEED_MACH_MEMORY_H
 	select HAVE_SCHED_CLOCK
+	select HAVE_SMP
 	help
 	  Support for boards based on the Texas Instruments Keystone family of
 	  SoCs.
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 7f2a04b..5f71e66 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -1,7 +1,9 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_ARCH_KEYSTONE=y
+CONFIG_SMP=y
 CONFIG_ARM_ARCH_TIMER=y
+CONFIG_NR_CPUS=4
 CONFIG_AEABI=y
 CONFIG_HIGHMEM=y
 CONFIG_VFP=y
diff --git a/arch/arm/mach-keystone/Makefile b/arch/arm/mach-keystone/Makefile
index d4671d5..3f6b8ab 100644
--- a/arch/arm/mach-keystone/Makefile
+++ b/arch/arm/mach-keystone/Makefile
@@ -1 +1,2 @@
 obj-y					:= keystone.o
+obj-$(CONFIG_SMP)			+= platsmp.o
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
index 702c184..6a8ece9 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -26,6 +26,8 @@
 #include <asm/arch_timer.h>
 #include <asm/hardware/gic.h>
 
+#include "keystone.h"
+
 static struct map_desc io_desc[] = {
 	{
 		.virtual        = 0xfe800000UL,
@@ -73,6 +75,7 @@ static const char *keystone_match[] __initconst = {
 };
 
 DT_MACHINE_START(KEYSTONE, "Keystone")
+	smp_ops(keystone_smp_ops)
 	.map_io		= keystone_map_io,
 	.init_irq	= keystone_init_irq,
 	.timer		= &keystone_timer,
diff --git a/arch/arm/mach-keystone/keystone.h b/arch/arm/mach-keystone/keystone.h
new file mode 100644
index 0000000..71bd0f4
--- /dev/null
+++ b/arch/arm/mach-keystone/keystone.h
@@ -0,0 +1,23 @@
+/*
+ * Copyright 2010-2012 Texas Instruments, Inc.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef __KEYSTONE_H__
+#define __KEYSTONE_H__
+
+extern struct smp_ops keystone_smp_ops;
+extern void secondary_startup(void);
+
+#endif /* __KEYSTONE_H__ */
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
new file mode 100644
index 0000000..dbe7601
--- /dev/null
+++ b/arch/arm/mach-keystone/platsmp.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright 2012 Texas Instruments, Inc.
+ *
+ * Based on platsmp.c, Copyright 2010-2011 Calxeda, Inc.
+ * Based on platsmp.c, Copyright (C) 2002 ARM Ltd.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program.  If not, see <http://www.gnu.org/licenses/>.
+ */
+#include <linux/init.h>
+#include <linux/smp.h>
+#include <linux/io.h>
+
+#include <asm/smp_plat.h>
+#include <asm/smp_ops.h>
+#include <asm/hardware/gic.h>
+#include <asm/cacheflush.h>
+#include <asm/memory.h>
+
+#include "keystone.h"
+
+static void __init keystone_smp_init_cpus(void)
+{
+	unsigned int i, ncores;
+
+	ncores = 4;
+
+	/* sanity check */
+	if (ncores > NR_CPUS) {
+		pr_warn("restricted to %d cpus\n", NR_CPUS);
+		ncores = NR_CPUS;
+	}
+
+	for (i = 0; i < ncores; i++)
+		set_cpu_possible(i, true);
+
+	set_smp_cross_call(gic_raise_softirq);
+}
+
+static void __init keystone_smp_prepare_cpus(unsigned int max_cpus)
+{
+	/* nothing for now */
+}
+
+static void __cpuinit keystone_secondary_init(unsigned int cpu)
+{
+	gic_secondary_init(0);
+}
+
+static int __cpuinit
+keystone_boot_secondary(unsigned int cpu, struct task_struct *idle)
+{
+	unsigned long *ptr;
+	
+	ptr = phys_to_virt(0x800001f0);
+	ptr[cpu] = virt_to_idmap(&secondary_startup);
+	__cpuc_flush_dcache_area(ptr, sizeof(ptr) * 4);
+
+	return 0;
+}
+
+struct smp_ops keystone_smp_ops __initdata = {
+	smp_init_ops(keystone)
+	smp_secondary_ops(keystone)
+};
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* [RFC v2 22/22] ARM: keystone: add switch over to high physical address range
  2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
                   ` (20 preceding siblings ...)
  2012-08-11  1:25 ` [RFC v2 21/22] ARM: keystone: enable SMP on Keystone machines Cyril Chemparathy
@ 2012-08-11  1:25 ` Cyril Chemparathy
  21 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-11  1:25 UTC (permalink / raw)
  To: linux-kernel, linux-arm-kernel
  Cc: arnd, catalin.marinas, grant.likely, nico, linux, will.deacon,
	Cyril Chemparathy, Vitaly Andrianov

Keystone platforms have their physical memory mapped at an address outside the
32-bit physical range.  A Keystone machine with 16G of RAM would find its
memory at 0x0800000000 - 0x0bffffffff.

For boot purposes, the interconnect supports a limited alias of some of this
memory within the 32-bit addressable space (0x80000000 - 0xffffffff).  This
aliasing is implemented in hardware, and is not intended to be used much
beyond boot.  For instance, DMA coherence does not work when running out of
this aliased address space.

Therefore, we've taken the approach of booting out of the low physical address
range, and subsequently we switch over to the high range once we're safely
inside machine specific territory.  This patch implements this switch over
mechanism, which involves rewiring the TTBRs and page tables to point to the
new physical address space.

Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
Signed-off-by: Cyril Chemparathy <cyril@ti.com>
---
 arch/arm/Kconfig                             |    1 +
 arch/arm/boot/dts/keystone-sim.dts           |    8 +++---
 arch/arm/configs/keystone_defconfig          |    1 +
 arch/arm/mach-keystone/include/mach/memory.h |   25 +++++++++++++++++
 arch/arm/mach-keystone/keystone.c            |   39 ++++++++++++++++++++++++++
 arch/arm/mach-keystone/platsmp.c             |   16 +++++++++--
 6 files changed, 83 insertions(+), 7 deletions(-)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 37b4e9c..18ffff7 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -417,6 +417,7 @@ config ARCH_KEYSTONE
 	select NEED_MACH_MEMORY_H
 	select HAVE_SCHED_CLOCK
 	select HAVE_SMP
+	select ZONE_DMA if ARM_LPAE
 	help
 	  Support for boards based on the Texas Instruments Keystone family of
 	  SoCs.
diff --git a/arch/arm/boot/dts/keystone-sim.dts b/arch/arm/boot/dts/keystone-sim.dts
index acec30f8..17ee473 100644
--- a/arch/arm/boot/dts/keystone-sim.dts
+++ b/arch/arm/boot/dts/keystone-sim.dts
@@ -4,8 +4,8 @@
 / {
 	model = "Texas Instruments Keystone 2 SoC";
 	compatible = "ti,keystone-evm";
-	#address-cells = <1>;
-	#size-cells = <1>;
+	#address-cells = <2>;
+	#size-cells = <2>;
 	interrupt-parent = <&gic>;
 
 	aliases {
@@ -13,11 +13,11 @@
 	};
 
 	chosen {
-		bootargs = "console=ttyS0,115200n8 debug earlyprintk lpj=50000 rdinit=/bin/ash rw root=/dev/ram0 initrd=0x85000000,2M";
+		bootargs = "console=ttyS0,115200n8 debug earlyprintk lpj=50000 rdinit=/bin/ash rw root=/dev/ram0 initrd=0x805000000,2M";
 	};
 
 	memory {
-		reg = <0x80000000 0x8000000>;
+		reg = <0x00000008 0x00000000 0x00000000 0x8000000>;
 	};
 
 	cpus {
diff --git a/arch/arm/configs/keystone_defconfig b/arch/arm/configs/keystone_defconfig
index 5f71e66..8ea3b96 100644
--- a/arch/arm/configs/keystone_defconfig
+++ b/arch/arm/configs/keystone_defconfig
@@ -1,6 +1,7 @@
 CONFIG_EXPERIMENTAL=y
 CONFIG_BLK_DEV_INITRD=y
 CONFIG_ARCH_KEYSTONE=y
+CONFIG_ARM_LPAE=y
 CONFIG_SMP=y
 CONFIG_ARM_ARCH_TIMER=y
 CONFIG_NR_CPUS=4
diff --git a/arch/arm/mach-keystone/include/mach/memory.h b/arch/arm/mach-keystone/include/mach/memory.h
index 7c78b1e..a5f7a1a 100644
--- a/arch/arm/mach-keystone/include/mach/memory.h
+++ b/arch/arm/mach-keystone/include/mach/memory.h
@@ -19,4 +19,29 @@
 #define MAX_PHYSMEM_BITS	36
 #define SECTION_SIZE_BITS	34
 
+#define KEYSTONE_LOW_PHYS_START		0x80000000ULL
+#define KEYSTONE_LOW_PHYS_SIZE		0x80000000ULL /* 2G */
+#define KEYSTONE_LOW_PHYS_END		(KEYSTONE_LOW_PHYS_START + \
+					 KEYSTONE_LOW_PHYS_SIZE - 1)
+
+#define KEYSTONE_HIGH_PHYS_START	0x800000000ULL
+#define KEYSTONE_HIGH_PHYS_SIZE		0x400000000ULL	/* 16G */
+#define KEYSTONE_HIGH_PHYS_END		(KEYSTONE_HIGH_PHYS_START + \
+					 KEYSTONE_HIGH_PHYS_SIZE - 1)
+#ifdef CONFIG_ARM_LPAE
+
+#ifndef __ASSEMBLY__
+
+static inline phys_addr_t __virt_to_idmap(unsigned long x)
+{
+	return (phys_addr_t)(x) - CONFIG_PAGE_OFFSET +
+		KEYSTONE_LOW_PHYS_START;
+}
+
+#define virt_to_idmap(x)	__virt_to_idmap((unsigned long)(x))
+
+#endif /* __ASSEMBLY__ */
+
+#endif /* CONFIG_ARM_LPAE */
+
 #endif /* __ASM_MACH_MEMORY_H */
diff --git a/arch/arm/mach-keystone/keystone.c b/arch/arm/mach-keystone/keystone.c
index 6a8ece9..c4be7a7 100644
--- a/arch/arm/mach-keystone/keystone.c
+++ b/arch/arm/mach-keystone/keystone.c
@@ -74,6 +74,41 @@ static const char *keystone_match[] __initconst = {
 	NULL,
 };
 
+static void __init keystone_init_meminfo(void)
+{
+	bool lpae = IS_ENABLED(CONFIG_ARM_LPAE);
+	bool pvpatch = IS_ENABLED(CONFIG_ARM_PATCH_PHYS_VIRT);
+	phys_addr_t offset = PHYS_OFFSET - KEYSTONE_LOW_PHYS_START;
+	phys_addr_t mem_start, mem_end;
+
+	BUG_ON(meminfo.nr_banks < 1);
+	mem_start = meminfo.bank[0].start;
+	mem_end = mem_start + meminfo.bank[0].size - 1;
+
+	/* nothing to do if we are running out of the <32-bit space */
+	if (mem_start >= KEYSTONE_LOW_PHYS_START &&
+	    mem_end   <= KEYSTONE_LOW_PHYS_END)
+		return;
+
+	if (!lpae || !pvpatch) {
+		panic("Enable %s%s%s to run outside 32-bit space\n",
+		      !lpae ? __stringify(CONFIG_ARM_LPAE) : "",
+		      (!lpae && !pvpatch) ? " and " : "",
+		      !pvpatch ? __stringify(CONFIG_ARM_PATCH_PHYS_VIRT) : "");
+	}
+
+	if (mem_start < KEYSTONE_HIGH_PHYS_START ||
+	    mem_end   > KEYSTONE_HIGH_PHYS_END) {
+		panic("Invalid address space for memory (%08llx-%08llx)\n",
+		      mem_start, mem_end);
+	}
+
+	offset += KEYSTONE_HIGH_PHYS_START;
+	pr_info("switching to high address space at 0x%llx\n", offset);
+	__pv_phys_offset = offset;
+	__pv_offset      = offset - PAGE_OFFSET;
+}
+
 DT_MACHINE_START(KEYSTONE, "Keystone")
 	smp_ops(keystone_smp_ops)
 	.map_io		= keystone_map_io,
@@ -82,4 +117,8 @@ DT_MACHINE_START(KEYSTONE, "Keystone")
 	.handle_irq	= gic_handle_irq,
 	.init_machine	= keystone_init,
 	.dt_compat	= keystone_match,
+	.init_meminfo	= keystone_init_meminfo,
+#ifdef CONFIG_ZONE_DMA
+	.dma_zone_size	= SZ_2G,
+#endif
 MACHINE_END
diff --git a/arch/arm/mach-keystone/platsmp.c b/arch/arm/mach-keystone/platsmp.c
index dbe7601..0151906 100644
--- a/arch/arm/mach-keystone/platsmp.c
+++ b/arch/arm/mach-keystone/platsmp.c
@@ -24,6 +24,7 @@
 #include <asm/smp_ops.h>
 #include <asm/hardware/gic.h>
 #include <asm/cacheflush.h>
+#include <asm/tlbflush.h>
 #include <asm/memory.h>
 
 #include "keystone.h"
@@ -51,17 +52,26 @@ static void __init keystone_smp_prepare_cpus(unsigned int max_cpus)
 	/* nothing for now */
 }
 
+static void __cpuinit keystone_secondary_initmem(void)
+{
+#ifdef CONFIG_ARM_LPAE
+	pgd_t *pgd0 = pgd_offset_k(0);
+	cpu_set_ttbr(1, __pa(pgd0) + TTBR1_OFFSET);
+	local_flush_tlb_all();
+#endif
+}
+
 static void __cpuinit keystone_secondary_init(unsigned int cpu)
 {
 	gic_secondary_init(0);
+	keystone_secondary_initmem();
 }
 
 static int __cpuinit
 keystone_boot_secondary(unsigned int cpu, struct task_struct *idle)
 {
-	unsigned long *ptr;
-	
-	ptr = phys_to_virt(0x800001f0);
+	unsigned long *ptr = (unsigned long *)(PAGE_OFFSET + 0x1f0);
+
 	ptr[cpu] = virt_to_idmap(&secondary_startup);
 	__cpuc_flush_dcache_area(ptr, sizeof(ptr) * 4);
 
-- 
1.7.9.5


^ permalink raw reply related	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 01/22] ARM: add mechanism for late code patching
  2012-08-11  1:24 ` [PATCH v2 01/22] ARM: add mechanism for late code patching Cyril Chemparathy
@ 2012-08-12  2:22   ` Nicolas Pitre
  2012-08-12 18:13     ` Cyril Chemparathy
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  2:22 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> The original phys_to_virt/virt_to_phys patching implementation relied on early
> patching prior to MMU initialization.  On PAE systems running out of >4G
> address space, this would have entailed an additional round of patching after
> switching over to the high address space.
> 
> The approach implemented here conceptually extends the original PHYS_OFFSET
> patching implementation with the introduction of "early" patch stubs.  Early
> patch code is required to be functional out of the box, even before the patch
> is applied.  This is implemented by inserting functional (but inefficient)
> load code into the .runtime.patch.code init section.  Having functional code
> out of the box then allows us to defer the init time patch application until
> later in the init sequence.
> 
> In addition to fitting better with our need for physical address-space
> switch-over, this implementation should be somewhat more extensible by virtue
> of its more readable (and hackable) C implementation.  This should prove
> useful for other similar init time specialization needs, especially in light
> of our multi-platform kernel initiative.
> 
> This code has been boot tested in both ARM and Thumb-2 modes on an ARMv7
> (Cortex-A8) device.
> 
> Note: the obtuse use of stringified symbols in patch_stub() and
> early_patch_stub() is intentional.  Theoretically this should have been
> accomplished with formal operands passed into the asm block, but this requires
> the use of the 'c' modifier for instantiating the long (e.g. .long %c0).
> However, the 'c' modifier has been found to ICE certain versions of GCC, and
> therefore we resort to stringified symbols here.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>

Reviewed-by: Nicolas Pitre <nico@linaro.org>


> ---
>  arch/arm/Kconfig                     |    3 +
>  arch/arm/include/asm/module.h        |    7 ++
>  arch/arm/include/asm/runtime-patch.h |  175 +++++++++++++++++++++++++++++++
>  arch/arm/kernel/Makefile             |    1 +
>  arch/arm/kernel/module.c             |    4 +
>  arch/arm/kernel/runtime-patch.c      |  189 ++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/setup.c              |    3 +
>  arch/arm/kernel/vmlinux.lds.S        |   10 ++
>  8 files changed, 392 insertions(+)
>  create mode 100644 arch/arm/include/asm/runtime-patch.h
>  create mode 100644 arch/arm/kernel/runtime-patch.c
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index e91c7cd..d0a04ad 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -61,6 +61,9 @@ config ARM
>  config ARM_HAS_SG_CHAIN
>  	bool
>  
> +config ARM_RUNTIME_PATCH
> +	bool
> +
>  config NEED_SG_DMA_LENGTH
>  	bool
>  
> diff --git a/arch/arm/include/asm/module.h b/arch/arm/include/asm/module.h
> index 6c6809f..2090486 100644
> --- a/arch/arm/include/asm/module.h
> +++ b/arch/arm/include/asm/module.h
> @@ -43,9 +43,16 @@ struct mod_arch_specific {
>  #define MODULE_ARCH_VERMAGIC_ARMTHUMB ""
>  #endif
>  
> +#ifdef CONFIG_ARM_RUNTIME_PATCH
> +#define MODULE_ARCH_VERMAGIC_RT_PATCH "rt-patch "
> +#else
> +#define MODULE_ARCH_VERMAGIC_RT_PATCH ""
> +#endif
> +
>  #define MODULE_ARCH_VERMAGIC \
>  	MODULE_ARCH_VERMAGIC_ARMVSN \
>  	MODULE_ARCH_VERMAGIC_ARMTHUMB \
> +	MODULE_ARCH_VERMAGIC_RT_PATCH \
>  	MODULE_ARCH_VERMAGIC_P2V
>  
>  #endif /* _ASM_ARM_MODULE_H */
> diff --git a/arch/arm/include/asm/runtime-patch.h b/arch/arm/include/asm/runtime-patch.h
> new file mode 100644
> index 0000000..6c6e8a2
> --- /dev/null
> +++ b/arch/arm/include/asm/runtime-patch.h
> @@ -0,0 +1,175 @@
> +/*
> + * arch/arm/include/asm/runtime-patch.h
> + * Note: this file should not be included by non-asm/.h files
> + *
> + * Copyright 2012 Texas Instruments, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#ifndef __ASM_ARM_RUNTIME_PATCH_H
> +#define __ASM_ARM_RUNTIME_PATCH_H
> +
> +#include <linux/stringify.h>
> +
> +#ifndef __ASSEMBLY__
> +
> +#ifdef CONFIG_ARM_RUNTIME_PATCH
> +
> +struct patch_info {
> +	void	*insn;
> +	u16	 type;
> +	u8	 insn_size;
> +	u8	 data_size;
> +	u32	 data[0];
> +};
> +
> +#define patch_next(p)		((void *)(p) + sizeof(*(p)) + (p)->data_size)
> +
> +#define PATCH_TYPE_MASK		0x00ff
> +#define PATCH_IMM8		0x0001
> +
> +#define PATCH_EARLY		0x8000
> +
> +#define patch_stub(type, code, patch_data, ...)				\
> +	__asm__("@ patch stub\n"					\
> +		"1:\n"							\
> +		code							\
> +		"2:\n"							\
> +		"	.pushsection .runtime.patch.table, \"a\"\n"	\
> +		"3:\n"							\
> +		"	.word 1b\n"					\
> +		"	.hword (" __stringify(type) ")\n"		\
> +		"	.byte (2b-1b)\n"				\
> +		"	.byte (5f-4f)\n"				\
> +		"4:\n"							\
> +		patch_data						\
> +		"	.align\n"					\
> +		"5:\n"							\
> +		"	.popsection\n"					\
> +		__VA_ARGS__)
> +
> +#define early_patch_stub(type, code, patch_data, ...)			\
> +	__asm__("@ patch stub\n"					\
> +		"1:\n"							\
> +		"	b	6f\n"					\
> +		"2:\n"							\
> +		"	.pushsection .runtime.patch.table, \"a\"\n"	\
> +		"3:\n"							\
> +		"	.word 1b\n"					\
> +		"	.hword (" __stringify(type | PATCH_EARLY) ")\n"	\
> +		"	.byte (2b-1b)\n"				\
> +		"	.byte (5f-4f)\n"				\
> +		"4:\n"							\
> +		patch_data						\
> +		"	.align\n"					\
> +		"5:\n"							\
> +		"	.popsection\n"					\
> +		"	.pushsection .runtime.patch.code, \"ax\"\n"	\
> +		"6:\n"							\
> +		code							\
> +		"	b 2b\n"						\
> +		"	.popsection\n"					\
> +		__VA_ARGS__)
> +
> +/* constant used to force encoding */
> +#define __IMM8		(0x81 << 24)
> +
> +/*
> + * patch_imm8() - init-time specialized binary operation (imm8 operand)
> + *		  This effectively does: to = from "insn" sym,
> + *		  where the value of sym is fixed at init-time, and is patched
> + *		  in as an immediate operand.  This value must be
> + *		  representible as an 8-bit quantity with an optional
> + *		  rotation.
> + *
> + *		  The stub code produced by this variant is non-functional
> + *		  prior to patching.  Use early_patch_imm8() if you need the
> + *		  code to be functional early on in the init sequence.
> + */
> +#define patch_imm8(insn, to, from, sym, offset)				\
> +	patch_stub(PATCH_IMM8,						\
> +		   /* code */						\
> +		   insn " %0, %1, %2\n",				\
> +		   /* patch_data */					\
> +		   ".long " __stringify(sym + offset) "\n"		\
> +		   insn " %0, %1, %2\n",				\
> +		   : "=r" (to)						\
> +		   : "r" (from), "I" (__IMM8), "m" (sym)		\
> +		   : "cc")
> +
> +/*
> + * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
> + */
> +#define patch_imm8_mov(insn, to, sym, offset)				\
> +	patch_stub(PATCH_IMM8,						\
> +		   /* code */						\
> +		   insn " %0, %1\n",					\
> +		   /* patch_data */					\
> +		   ".long " __stringify(sym + offset) "\n"		\
> +		   insn " %0, %1\n",					\
> +		   : "=r" (to)						\
> +		   : "I" (__IMM8), "m" (sym)				\
> +		   : "cc")
> +
> +/*
> + * early_patch_imm8() - early functional variant of patch_imm8() above.  The
> + *			same restrictions on the constant apply here.  This
> + *			version emits workable (albeit inefficient) code at
> + *			compile-time, and therefore functions even prior to
> + *			patch application.
> + */
> +#define early_patch_imm8(insn, to, from, sym, offset)			\
> +	early_patch_stub(PATCH_IMM8,					\
> +			 /* code */					\
> +			 "ldr	%0, =" __stringify(sym + offset) "\n"	\
> +			 "ldr	%0, [%0]\n"				\
> +			 insn " %0, %1, %0\n",				\
> +			 /* patch_data */				\
> +			 ".long " __stringify(sym + offset) "\n"	\
> +			 insn " %0, %1, %2\n",				\
> +			 : "=&r" (to)					\
> +			 : "r" (from), "I" (__IMM8), "m" (sym)		\
> +			 : "cc")
> +
> +#define early_patch_imm8_mov(insn, to, sym, offset)			\
> +	early_patch_stub(PATCH_IMM8,					\
> +			 /* code */					\
> +			 "ldr	%0, =" __stringify(sym + offset) "\n"	\
> +			 "ldr	%0, [%0]\n"				\
> +			 insn " %0, %0\n",				\
> +			 /* patch_data */				\
> +			 ".long " __stringify(sym + offset) "\n"	\
> +			 insn " %0, %1\n",				\
> +			 : "=&r" (to)					\
> +			 : "I" (__IMM8), "m" (sym)			\
> +			 : "cc")
> +
> +int runtime_patch(const void *table, unsigned size);
> +void runtime_patch_kernel(void);
> +
> +#else
> +
> +static inline int runtime_patch(const void *table, unsigned size)
> +{
> +	return 0;
> +}
> +
> +static inline void runtime_patch_kernel(void)
> +{
> +}
> +
> +#endif /* CONFIG_ARM_RUNTIME_PATCH */
> +
> +#endif /* __ASSEMBLY__ */
> +
> +#endif /* __ASM_ARM_RUNTIME_PATCH_H */
> diff --git a/arch/arm/kernel/Makefile b/arch/arm/kernel/Makefile
> index 7ad2d5c..12cc1e7 100644
> --- a/arch/arm/kernel/Makefile
> +++ b/arch/arm/kernel/Makefile
> @@ -81,5 +81,6 @@ endif
>  head-y			:= head$(MMUEXT).o
>  obj-$(CONFIG_DEBUG_LL)	+= debug.o
>  obj-$(CONFIG_EARLY_PRINTK)	+= early_printk.o
> +obj-$(CONFIG_ARM_RUNTIME_PATCH)	+= runtime-patch.o
>  
>  extra-y := $(head-y) vmlinux.lds
> diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
> index 1e9be5d..dcebf80 100644
> --- a/arch/arm/kernel/module.c
> +++ b/arch/arm/kernel/module.c
> @@ -24,6 +24,7 @@
>  #include <asm/sections.h>
>  #include <asm/smp_plat.h>
>  #include <asm/unwind.h>
> +#include <asm/runtime-patch.h>
>  
>  #ifdef CONFIG_XIP_KERNEL
>  /*
> @@ -321,6 +322,9 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
>  	if (s)
>  		fixup_pv_table((void *)s->sh_addr, s->sh_size);
>  #endif
> +	s = find_mod_section(hdr, sechdrs, ".runtime.patch.table");
> +	if (s)
> +		runtime_patch((void *)s->sh_addr, s->sh_size);
>  	s = find_mod_section(hdr, sechdrs, ".alt.smp.init");
>  	if (s && !is_smp())
>  #ifdef CONFIG_SMP_ON_UP
> diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
> new file mode 100644
> index 0000000..fd37a2b
> --- /dev/null
> +++ b/arch/arm/kernel/runtime-patch.c
> @@ -0,0 +1,189 @@
> +/*
> + * arch/arm/kernel/runtime-patch.c
> + *
> + * Copyright 2012 Texas Instruments, Inc.
> + *
> + * This program is free software; you can redistribute it and/or modify it
> + * under the terms and conditions of the GNU General Public License,
> + * version 2, as published by the Free Software Foundation.
> + *
> + * This program is distributed in the hope it will be useful, but WITHOUT
> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
> + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
> + * more details.
> + *
> + * You should have received a copy of the GNU General Public License along with
> + * this program.  If not, see <http://www.gnu.org/licenses/>.
> + */
> +#include <linux/kernel.h>
> +#include <linux/sched.h>
> +
> +#include <asm/opcodes.h>
> +#include <asm/cacheflush.h>
> +#include <asm/runtime-patch.h>
> +
> +static inline void flush_icache_insn(void *insn_ptr, int bytes)
> +{
> +	unsigned long insn_addr = (unsigned long)insn_ptr;
> +	flush_icache_range(insn_addr, insn_addr + bytes - 1);
> +}
> +
> +#ifdef CONFIG_THUMB2_KERNEL
> +
> +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
> +{
> +	u32 op, rot, val;
> +	const u32 supported_ops = (BIT(0)  | /* and */
> +				   BIT(1)  | /* bic */
> +				   BIT(2)  | /* orr/mov */
> +				   BIT(3)  | /* orn/mvn */
> +				   BIT(4)  | /* eor */
> +				   BIT(8)  | /* add */
> +				   BIT(10) | /* adc */
> +				   BIT(11) | /* sbc */
> +				   BIT(12) | /* sub */
> +				   BIT(13)); /* rsb */
> +
> +	insn = __mem_to_opcode_thumb32(insn);
> +
> +	if (!__opcode_is_thumb32(insn)) {
> +		pr_err("patch: invalid thumb2 insn %08x\n", insn);
> +		return -EINVAL;
> +	}
> +
> +	/* allow only data processing (immediate)
> +	 * 1111 0x0x xxx0 xxxx 0xxx xxxx xxxx xxxx */
> +	if ((insn & 0xfa008000) != 0xf0000000) {
> +		pr_err("patch: unknown insn %08x\n", insn);
> +		return -EINVAL;
> +	}
> +
> +	/* extract op code */
> +	op = (insn >> 21) & 0xf;
> +
> +	/* disallow unsupported opcodes */
> +	if ((supported_ops & BIT(op)) == 0) {
> +		pr_err("patch: unsupported opcode %x\n", op);
> +		return -EINVAL;
> +	}
> +
> +	if (imm <= 0xff) {
> +		rot = 0;
> +		val = imm;
> +	} else {
> +		rot = 32 - fls(imm); /* clz */
> +		if (imm & ~(0xff000000 >> rot)) {
> +			pr_err("patch: constant overflow %08x\n", imm);
> +			return -EINVAL;
> +		}
> +		val  = (imm >> (24 - rot)) & 0x7f;
> +		rot += 8; /* encoded i:imm3:a */
> +
> +		/* pack least-sig rot bit into most-sig val bit */
> +		val |= (rot & 1) << 7;
> +		rot >>= 1;
> +	}
> +
> +	*ninsn  = insn & ~(BIT(26) | 0x7 << 12 | 0xff);
> +	*ninsn |= (rot >> 3) << 26;	/* field "i" */
> +	*ninsn |= (rot & 0x7) << 12;	/* field "imm3" */
> +	*ninsn |= val;
> +	*ninsn  = __opcode_to_mem_thumb32(*ninsn);
> +
> +	return 0;
> +}
> +
> +#else
> +
> +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
> +{
> +	u32 rot, val, op;
> +
> +	insn = __mem_to_opcode_arm(insn);
> +
> +	/* disallow special unconditional instructions
> +	 * 1111 xxxx xxxx xxxx xxxx xxxx xxxx xxxx */
> +	if ((insn >> 24) == 0xf) {
> +		pr_err("patch: unconditional insn %08x\n", insn);
> +		return -EINVAL;
> +	}
> +
> +	/* allow only data processing (immediate)
> +	 * xxxx 001x xxxx xxxx xxxx xxxx xxxx xxxx */
> +	if (((insn >> 25) & 0x3) != 1) {
> +		pr_err("patch: unknown insn %08x\n", insn);
> +		return -EINVAL;
> +	}
> +
> +	/* extract op code */
> +	op = (insn >> 20) & 0x1f;
> +
> +	/* disallow unsupported 10xxx op codes */
> +	if (((op >> 3) & 0x3) == 2) {
> +		pr_err("patch: unsupported opcode %08x\n", insn);
> +		return -EINVAL;
> +	}
> +
> +	rot = imm ? __ffs(imm) / 2 : 0;
> +	val = imm >> (rot * 2);
> +	rot = (-rot) & 0xf;
> +
> +	/* does this fit in 8-bit? */
> +	if (val > 0xff) {
> +		pr_err("patch: constant overflow %08x\n", imm);
> +		return -EINVAL;
> +	}
> +
> +	/* patch in new immediate and rotation */
> +	*ninsn = (insn & ~0xfff) | (rot << 8) | val;
> +	*ninsn = __opcode_to_mem_arm(*ninsn);
> +
> +	return 0;
> +}
> +
> +#endif	/* CONFIG_THUMB2_KERNEL */
> +
> +static int apply_patch_imm8(const struct patch_info *p)
> +{
> +	u32 *insn_ptr = p->insn;
> +	int ret;
> +
> +	if (p->insn_size != sizeof(u32) || p->data_size != 2 * sizeof(u32)) {
> +		pr_err("patch: bad patch, insn size %d, data size %d\n",
> +		       p->insn_size, p->data_size);
> +		return -EINVAL;
> +	}
> +
> +	ret = do_patch_imm8(p->data[1], *(u32 *)p->data[0], insn_ptr);
> +	if (ret < 0)
> +		return ret;
> +
> +	flush_icache_insn(insn_ptr, sizeof(u32));
> +
> +	return 0;
> +}
> +
> +int runtime_patch(const void *table, unsigned size)
> +{
> +	const struct patch_info *p = table, *end = (table + size);
> +
> +	for (p = table; p < end; p = patch_next(p)) {
> +		int type = p->type & PATCH_TYPE_MASK;
> +		int ret = -EINVAL;
> +
> +		if (type == PATCH_IMM8)
> +			ret = apply_patch_imm8(p);
> +		if (ret < 0)
> +			return ret;
> +	}
> +	return 0;
> +}
> +
> +void __init runtime_patch_kernel(void)
> +{
> +	extern unsigned __runtime_patch_table_begin, __runtime_patch_table_end;
> +	const void *start = &__runtime_patch_table_begin;
> +	const void *end   = &__runtime_patch_table_end;
> +
> +	BUG_ON(runtime_patch(start, end - start));
> +}
> diff --git a/arch/arm/kernel/setup.c b/arch/arm/kernel/setup.c
> index a81dcec..669bbf0 100644
> --- a/arch/arm/kernel/setup.c
> +++ b/arch/arm/kernel/setup.c
> @@ -55,6 +55,7 @@
>  #include <asm/traps.h>
>  #include <asm/unwind.h>
>  #include <asm/memblock.h>
> +#include <asm/runtime-patch.h>
>  
>  #if defined(CONFIG_DEPRECATED_PARAM_STRUCT)
>  #include "compat.h"
> @@ -998,6 +999,8 @@ void __init setup_arch(char **cmdline_p)
>  
>  	if (mdesc->init_early)
>  		mdesc->init_early();
> +
> +	runtime_patch_kernel();
>  }
>  
>  
> diff --git a/arch/arm/kernel/vmlinux.lds.S b/arch/arm/kernel/vmlinux.lds.S
> index 36ff15b..ea35ca0 100644
> --- a/arch/arm/kernel/vmlinux.lds.S
> +++ b/arch/arm/kernel/vmlinux.lds.S
> @@ -167,6 +167,16 @@ SECTIONS
>  		*(.pv_table)
>  		__pv_table_end = .;
>  	}
> +	.init.runtime_patch_table : {
> +		__runtime_patch_table_begin = .;
> +		*(.runtime.patch.table)
> +		__runtime_patch_table_end = .;
> +	}
> +	.init.runtime_patch_code : {
> +		__runtime_patch_code_begin = .;
> +		*(.runtime.patch.code)
> +		__runtime_patch_code_end = .;
> +	}
>  	.init.data : {
>  #ifndef CONFIG_XIP_KERNEL
>  		INIT_DATA
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/22] ARM: add self test for runtime patch mechanism
  2012-08-11  1:24 ` [PATCH v2 02/22] ARM: add self test for runtime patch mechanism Cyril Chemparathy
@ 2012-08-12  2:35   ` Nicolas Pitre
  2012-08-12 16:32     ` Cyril Chemparathy
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  2:35 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch adds basic sanity tests to ensure that the instruction patching
> results in valid instruction encodings.  This is done by verifying the output
> of the patch process against a vector of assembler generated instructions at
> init time.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> ---
>  arch/arm/Kconfig                |   12 ++++++++++++
>  arch/arm/kernel/runtime-patch.c |   41 +++++++++++++++++++++++++++++++++++++++
>  2 files changed, 53 insertions(+)
> 
> diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
> index d0a04ad..7e552dc 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -211,6 +211,18 @@ config ARM_PATCH_PHYS_VIRT
>  	  this feature (eg, building a kernel for a single machine) and
>  	  you need to shrink the kernel to the minimal size.
>  
> +config ARM_RUNTIME_PATCH_TEST
> +	bool "Self test runtime patching mechanism" if ARM_RUNTIME_PATCH
> +	default y
> +	help
> +	  Select this to enable init time self checking for the runtime kernel
> +	  patching mechanism.  This enables an ISA specific set of tests that
> +	  ensure that the instructions generated by the patch process are
> +	  consistent with those generated by the assembler at compile time.
> +
> +	  Only disable this option if you need to shrink the kernel to the
> +	  minimal size.
> +
>  config NEED_MACH_IO_H
>  	bool
>  	help
> diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
> index fd37a2b..c471d8c 100644
> --- a/arch/arm/kernel/runtime-patch.c
> +++ b/arch/arm/kernel/runtime-patch.c
> @@ -163,6 +163,44 @@ static int apply_patch_imm8(const struct patch_info *p)
>  	return 0;
>  }
>  
> +#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST
> +static void __init __used __naked __patch_test_code_imm8(void)
> +{
> +	__asm__ __volatile__ (
> +		"	.irp	shift1, 0, 6, 12, 18\n"
> +		"	.irp	shift2, 0, 1, 2, 3, 4, 5\n"
> +		"	add     r1, r2, #(0x41 << (\\shift1 + \\shift2))\n"
> +		"	.endr\n"
> +		"	.endr\n"


Maybe adding a "add r1, r2 #0x81 << 24" here might be a good thing since 
this is the most used case but missing from the above.

> +		"	.word	0\n"
> +		: : :
> +	);
> +}
> +
> +static void __init test_patch_imm8(void)
> +{
> +	u32 test_code_addr = (u32)(&__patch_test_code_imm8);
> +	u32 *test_code = (u32 *)(test_code_addr & ~0x3);

Why this masking?  With Thumb2 you may find functions starting at 
halfword aligned addresses.  Only the LSB (indicating thumb mode) should 
be masked out.

> +	int i, ret;
> +	u32 ninsn, insn;
> +
> +	insn = test_code[0];
> +	for (i = 0; test_code[i]; i++) {
> +		ret = do_patch_imm8(insn, 0x41 << i, &ninsn);
> +		if (ret < 0)
> +			pr_err("runtime patch (imm8): failed at shift %d\n", i);
> +		else if (ninsn != test_code[i])
> +			pr_err("runtime patch (imm8): failed, need %x got %x\n",
> +			       test_code[i], ninsn);
> +	}
> +}
> +
> +static void __init runtime_patch_test(void)
> +{
> +	test_patch_imm8();
> +}
> +#endif
> +
>  int runtime_patch(const void *table, unsigned size)
>  {
>  	const struct patch_info *p = table, *end = (table + size);
> @@ -185,5 +223,8 @@ void __init runtime_patch_kernel(void)
>  	const void *start = &__runtime_patch_table_begin;
>  	const void *end   = &__runtime_patch_table_end;
>  
> +#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST
> +	runtime_patch_test();
> +#endif
>  	BUG_ON(runtime_patch(start, end - start));
>  }
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching
  2012-08-11  1:24 ` [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
@ 2012-08-12  3:03   ` Nicolas Pitre
  2012-08-12 17:34     ` Cyril Chemparathy
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  3:03 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, Arnd Bergmann, Catalin Marinas,
	Grant Likely, Russell King - ARM Linux, Will Deacon

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch replaces the original physical offset patching implementation
> with one that uses the newly added patching framework.  In the process, we now
> unconditionally initialize the __pv_phys_offset and __pv_offset globals in the
> head.S code.

This last sentence is now wrong.

[...]
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index e965f1b..3d93779 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -18,6 +18,8 @@
>  #include <linux/types.h>
>  #include <linux/sizes.h>
>  
> +#include <asm/runtime-patch.h>
> +
>  #ifdef CONFIG_NEED_MACH_MEMORY_H
>  #include <mach/memory.h>
>  #endif
> @@ -151,35 +153,21 @@
>  #ifndef __virt_to_phys
>  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
>  
> -/*
> - * Constants used to force the right instruction encodings and shifts
> - * so that all we need to do is modify the 8-bit constant field.
> - */
> -#define __PV_BITS_31_24	0x81000000
> -
> -extern unsigned long __pv_phys_offset;
> -#define PHYS_OFFSET __pv_phys_offset
> -
> -#define __pv_stub(from,to,instr,type)			\
> -	__asm__("@ __pv_stub\n"				\
> -	"1:	" instr "	%0, %1, %2\n"		\
> -	"	.pushsection .pv_table,\"a\"\n"		\
> -	"	.long	1b\n"				\
> -	"	.popsection\n"				\
> -	: "=r" (to)					\
> -	: "r" (from), "I" (type))
> +extern unsigned long	__pv_offset;
> +extern unsigned long	__pv_phys_offset;
> +#define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)

What was wrong with the former PHYS_OFFSET = __pv_phys_offset ?

If you really want to have it optimized at run time, you could simply 
use your new stub to patch a mov instruction instead of going through 
__virt_to_phys which uses and add on top of a constant.

>  static inline unsigned long __virt_to_phys(unsigned long x)
>  {
>  	unsigned long t;
> -	__pv_stub(x, t, "add", __PV_BITS_31_24);
> +	early_patch_imm8("add", t, x, __pv_offset, 0);
>  	return t;
>  }
>  
>  static inline unsigned long __phys_to_virt(unsigned long x)
>  {
>  	unsigned long t;
> -	__pv_stub(x, t, "sub", __PV_BITS_31_24);
> +	early_patch_imm8("sub", t, x, __pv_offset, 0);
>  	return t;
>  }
>  #else
> diff --git a/arch/arm/kernel/armksyms.c b/arch/arm/kernel/armksyms.c
> index 60d3b73..6b388f8 100644
> --- a/arch/arm/kernel/armksyms.c
> +++ b/arch/arm/kernel/armksyms.c
> @@ -152,7 +152,3 @@ EXPORT_SYMBOL(mcount);
>  #endif
>  EXPORT_SYMBOL(__gnu_mcount_nc);
>  #endif
> -
> -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> -EXPORT_SYMBOL(__pv_phys_offset);
> -#endif
> diff --git a/arch/arm/kernel/head.S b/arch/arm/kernel/head.S
> index 3db960e..69a3c09 100644
> --- a/arch/arm/kernel/head.S
> +++ b/arch/arm/kernel/head.S
> @@ -117,7 +117,7 @@ ENTRY(stext)
>  	bl	__fixup_smp
>  #endif
>  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> -	bl	__fixup_pv_table
> +	bl	__fixup_pv_offsets
>  #endif
>  	bl	__create_page_tables
>  
> @@ -511,92 +511,29 @@ ENDPROC(fixup_smp)
>  
>  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
>  
> -/* __fixup_pv_table - patch the stub instructions with the delta between
> - * PHYS_OFFSET and PAGE_OFFSET, which is assumed to be 16MiB aligned and
> - * can be expressed by an immediate shifter operand. The stub instruction
> - * has a form of '(add|sub) rd, rn, #imm'.
> +/*
> + * __fixup_pv_offsets - update __pv_offset and __pv_phys_offset based on the
> + * runtime location of the kernel.
>   */
>  	__HEAD
> -__fixup_pv_table:
> +__fixup_pv_offsets:
>  	adr	r0, 1f
> -	ldmia	r0, {r3-r5, r7}
> +	ldmia	r0, {r3-r6}
>  	sub	r3, r0, r3	@ PHYS_OFFSET - PAGE_OFFSET
> -	add	r4, r4, r3	@ adjust table start address
> -	add	r5, r5, r3	@ adjust table end address
> -	add	r7, r7, r3	@ adjust __pv_phys_offset address
> -	str	r8, [r7]	@ save computed PHYS_OFFSET to __pv_phys_offset
> -	mov	r6, r3, lsr #24	@ constant for add/sub instructions
> -	teq	r3, r6, lsl #24 @ must be 16MiB aligned
> -THUMB(	it	ne		@ cross section branch )
> -	bne	__error
> -	str	r6, [r7, #4]	@ save to __pv_offset
> -	b	__fixup_a_pv_table
> -ENDPROC(__fixup_pv_table)
> +	add	r4, r4, r3	@ virt_to_phys(__pv_phys_offset)
> +	add	r5, r5, r3	@ virt_to_phys(__pv_offset)
> +	add	r6, r6, r3	@ virt_to_phys(PAGE_OFFSET) = PHYS_OFFSET
> +	str	r6, [r4]	@ save __pv_phys_offset
> +	str	r3, [r5]	@ save __pv_offset
> +	mov	pc, lr
> +ENDPROC(__fixup_pv_offsets)
>  
>  	.align
>  1:	.long	.
> -	.long	__pv_table_begin
> -	.long	__pv_table_end
> -2:	.long	__pv_phys_offset
> -
> -	.text
> -__fixup_a_pv_table:
> -#ifdef CONFIG_THUMB2_KERNEL
> -	lsls	r6, #24
> -	beq	2f
> -	clz	r7, r6
> -	lsr	r6, #24
> -	lsl	r6, r7
> -	bic	r6, #0x0080
> -	lsrs	r7, #1
> -	orrcs	r6, #0x0080
> -	orr	r6, r6, r7, lsl #12
> -	orr	r6, #0x4000
> -	b	2f
> -1:	add     r7, r3
> -	ldrh	ip, [r7, #2]
> -	and	ip, 0x8f00
> -	orr	ip, r6	@ mask in offset bits 31-24
> -	strh	ip, [r7, #2]
> -2:	cmp	r4, r5
> -	ldrcc	r7, [r4], #4	@ use branch for delay slot
> -	bcc	1b
> -	bx	lr
> -#else
> -	b	2f
> -1:	ldr	ip, [r7, r3]
> -	bic	ip, ip, #0x000000ff
> -	orr	ip, ip, r6	@ mask in offset bits 31-24
> -	str	ip, [r7, r3]
> -2:	cmp	r4, r5
> -	ldrcc	r7, [r4], #4	@ use branch for delay slot
> -	bcc	1b
> -	mov	pc, lr
> +	.long	__pv_phys_offset
> +	.long	__pv_offset
> +	.long	PAGE_OFFSET
>  #endif
> -ENDPROC(__fixup_a_pv_table)
> -
> -ENTRY(fixup_pv_table)
> -	stmfd	sp!, {r4 - r7, lr}
> -	ldr	r2, 2f			@ get address of __pv_phys_offset
> -	mov	r3, #0			@ no offset
> -	mov	r4, r0			@ r0 = table start
> -	add	r5, r0, r1		@ r1 = table size
> -	ldr	r6, [r2, #4]		@ get __pv_offset
> -	bl	__fixup_a_pv_table
> -	ldmfd	sp!, {r4 - r7, pc}
> -ENDPROC(fixup_pv_table)
>  
> -	.align
> -2:	.long	__pv_phys_offset
> -
> -	.data
> -	.globl	__pv_phys_offset
> -	.type	__pv_phys_offset, %object
> -__pv_phys_offset:
> -	.long	0
> -	.size	__pv_phys_offset, . - __pv_phys_offset
> -__pv_offset:
> -	.long	0
> -#endif
>  
>  #include "head-common.S"
> diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
> index dcebf80..ac13dd5 100644
> --- a/arch/arm/kernel/module.c
> +++ b/arch/arm/kernel/module.c
> @@ -317,11 +317,6 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
>  					         maps[i].txt_sec->sh_addr,
>  					         maps[i].txt_sec->sh_size);
>  #endif
> -#ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> -	s = find_mod_section(hdr, sechdrs, ".pv_table");
> -	if (s)
> -		fixup_pv_table((void *)s->sh_addr, s->sh_size);
> -#endif
>  	s = find_mod_section(hdr, sechdrs, ".runtime.patch.table");
>  	if (s)
>  		runtime_patch((void *)s->sh_addr, s->sh_size);

I missed this in the previous patch, but could you fail the module 
loading by returning an error if runtime_patch() fails?  That would take 
care of not accepting modules that might have been compiled with future 
runtime patching extensions that are not yet supported in an earlier 
kernel.

You also should remove the MODULE_ARCH_VERMAGIC_P2V definitions now that 
the corresponding code is no longer there.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion
  2012-08-11  1:24 ` [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
@ 2012-08-12  3:04   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  3:04 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch fixes up the types used when converting back and forth between
> physical and virtual addresses.
> 
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>

Reviewed-by: Nicolas Pitre <nico@linaro.org>

> ---
>  arch/arm/include/asm/memory.h |   26 ++++++++++++++++++--------
>  1 file changed, 18 insertions(+), 8 deletions(-)
> 
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index 3d93779..81e1714 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -157,22 +157,32 @@ extern unsigned long	__pv_offset;
>  extern unsigned long	__pv_phys_offset;
>  #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
>  
> -static inline unsigned long __virt_to_phys(unsigned long x)
> +static inline phys_addr_t __virt_to_phys(unsigned long x)
>  {
>  	unsigned long t;
>  	early_patch_imm8("add", t, x, __pv_offset, 0);
>  	return t;
>  }
>  
> -static inline unsigned long __phys_to_virt(unsigned long x)
> +static inline unsigned long __phys_to_virt(phys_addr_t x)
>  {
> -	unsigned long t;
> -	early_patch_imm8("sub", t, x, __pv_offset, 0);
> +	unsigned long t, xlo = x;
> +	early_patch_imm8("sub", t, xlo, __pv_offset, 0);
>  	return t;
>  }
> +
>  #else
> -#define __virt_to_phys(x)	((x) - PAGE_OFFSET + PHYS_OFFSET)
> -#define __phys_to_virt(x)	((x) - PHYS_OFFSET + PAGE_OFFSET)
> +
> +static inline phys_addr_t __virt_to_phys(unsigned long x)
> +{
> +	return (phys_addr_t)x - PAGE_OFFSET + PHYS_OFFSET;
> +}
> +
> +static inline unsigned long __phys_to_virt(phys_addr_t x)
> +{
> +	return x - PHYS_OFFSET + PAGE_OFFSET;
> +}
> +
>  #endif
>  #endif
>  
> @@ -207,14 +217,14 @@ static inline phys_addr_t virt_to_phys(const volatile void *x)
>  
>  static inline void *phys_to_virt(phys_addr_t x)
>  {
> -	return (void *)(__phys_to_virt((unsigned long)(x)));
> +	return (void *)__phys_to_virt(x);
>  }
>  
>  /*
>   * Drivers should NOT use these either.
>   */
>  #define __pa(x)			__virt_to_phys((unsigned long)(x))
> -#define __va(x)			((void *)__phys_to_virt((unsigned long)(x)))
> +#define __va(x)			((void *)__phys_to_virt((phys_addr_t)(x)))
>  #define pfn_to_kaddr(pfn)	__va((pfn) << PAGE_SHIFT)
>  
>  /*
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-08-11  1:24 ` [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
@ 2012-08-12  3:39   ` Nicolas Pitre
  2012-08-12 23:27     ` Cyril Chemparathy
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  3:39 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch adds support for 64-bit physical addresses in virt_to_phys()
> patching.  This does not do real 64-bit add/sub, but instead patches in the
> upper 32-bits of the phys_offset directly into the output of virt_to_phys.
> 
> There is no corresponding change on the phys_to_virt() side, because
> computations on the upper 32-bits would be discarded anyway.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> ---
>  arch/arm/include/asm/memory.h |   22 ++++++++++++++++++----
>  arch/arm/kernel/head.S        |    4 ++++
>  arch/arm/kernel/setup.c       |    2 +-
>  3 files changed, 23 insertions(+), 5 deletions(-)
> 
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index 81e1714..dc5fbf3 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -154,14 +154,28 @@
>  #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
>  
>  extern unsigned long	__pv_offset;
> -extern unsigned long	__pv_phys_offset;
> +extern phys_addr_t	__pv_phys_offset;
>  #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
>  
>  static inline phys_addr_t __virt_to_phys(unsigned long x)
>  {
> -	unsigned long t;
> -	early_patch_imm8("add", t, x, __pv_offset, 0);
> -	return t;
> +	unsigned long tlo, thi;
> +
> +	early_patch_imm8("add", tlo, x, __pv_offset, 0);
> +
> +#ifdef CONFIG_ARM_LPAE
> +	/*
> +	 * On LPAE, we do not _need_ to do 64-bit arithmetic because the high
> +	 * order 32 bits are never changed by the phys-virt offset.  We simply
> +	 * patch in the high order physical address bits instead.
> +	 */
> +#ifdef __ARMEB__
> +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
> +#else
> +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
> +#endif
> +#endif
> +	return (u64)tlo | (u64)thi << 32;
>  }

Hmmm...  I'm afraid this is going to be suboptimal when LPAE is not 
selected.

First of all, you do not need to cast tlo to a u64 in the return value.

Then, I'm not sure if the compiler is smart enough to see that the 
returned value is a phys_addr_t which can be a u32, and in this case the 
(u64)thi << 32 is going to be truncated right away, and therefore there 
is no point in emiting the corresponding instructions.

Furthermore, if LPAE is not defined, then thi never gets initialized and 
should produce a warning. Did you test compilation of the code with LPAE 
turned off?

I'd prefer something like this where more stuff is validated by the 
compiler:

static inline phys_addr_t __virt_to_phys(unsigned long x)
{
	unsigned long tlo, thi;
	phys_addr_t ret;

	early_patch_imm8("add", tlo, x, __pv_offset, 0);
	ret = tlo;

	if (sizeof(phys_addr_t) > 4) {
#ifdef __ARMEB__
		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
#else
		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
#endif
		ret |= ((u64)thi) << 32;
	}

	return ret);
}

This should let the compiler optimize things whether LPAE is enabledor 
not while validating both cases.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions
  2012-08-11  1:24 ` [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
@ 2012-08-12  3:57   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  3:57 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch applies to PAGE_MASK, PMD_MASK, and PGDIR_MASK, where forcing
> unsigned long math truncates the mask at the 32-bits.  This clearly does bad
> things on PAE systems.
> 
> This patch fixes this problem by defining these masks as signed quantities.
> We then rely on sign extension to do the right thing.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>

Reviewed-by: Nicolas Pitre <nico@linaro.org>

> ---
>  arch/arm/include/asm/page.h           |    2 +-
>  arch/arm/include/asm/pgtable-3level.h |    6 +++---
>  2 files changed, 4 insertions(+), 4 deletions(-)
> 
> diff --git a/arch/arm/include/asm/page.h b/arch/arm/include/asm/page.h
> index ecf9019..1e0fe08 100644
> --- a/arch/arm/include/asm/page.h
> +++ b/arch/arm/include/asm/page.h
> @@ -13,7 +13,7 @@
>  /* PAGE_SHIFT determines the page size */
>  #define PAGE_SHIFT		12
>  #define PAGE_SIZE		(_AC(1,UL) << PAGE_SHIFT)
> -#define PAGE_MASK		(~(PAGE_SIZE-1))
> +#define PAGE_MASK		(~((1 << PAGE_SHIFT) - 1))
>  
>  #ifndef __ASSEMBLY__
>  
> diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
> index b249035..ae39d11 100644
> --- a/arch/arm/include/asm/pgtable-3level.h
> +++ b/arch/arm/include/asm/pgtable-3level.h
> @@ -48,16 +48,16 @@
>  #define PMD_SHIFT		21
>  
>  #define PMD_SIZE		(1UL << PMD_SHIFT)
> -#define PMD_MASK		(~(PMD_SIZE-1))
> +#define PMD_MASK		(~((1 << PMD_SHIFT) - 1))
>  #define PGDIR_SIZE		(1UL << PGDIR_SHIFT)
> -#define PGDIR_MASK		(~(PGDIR_SIZE-1))
> +#define PGDIR_MASK		(~((1 << PGDIR_SHIFT) - 1))
>  
>  /*
>   * section address mask and size definitions.
>   */
>  #define SECTION_SHIFT		21
>  #define SECTION_SIZE		(1UL << SECTION_SHIFT)
> -#define SECTION_MASK		(~(SECTION_SIZE-1))
> +#define SECTION_MASK		(~((1 << SECTION_SHIFT) - 1))
>  
>  #define USER_PTRS_PER_PGD	(PAGE_OFFSET / PGDIR_SIZE)
>  
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size
  2012-08-11  1:24 ` [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
@ 2012-08-12  3:58   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  3:58 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> From: Vitaly Andrianov <vitalya@ti.com>
> 
> This patch fixes the initrd setup code to use phys_addr_t instead of assuming
> 32-bit addressing.  Without this we cannot boot on systems where initrd is
> located above the 4G physical address limit.
> 
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>

Acked-by: Nicolas Pitre <nico@linaro.org>

> ---
>  arch/arm/mm/init.c |   13 +++++++------
>  1 file changed, 7 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/mm/init.c b/arch/arm/mm/init.c
> index 19ba70b..bae9d05 100644
> --- a/arch/arm/mm/init.c
> +++ b/arch/arm/mm/init.c
> @@ -36,12 +36,13 @@
>  
>  #include "mm.h"
>  
> -static unsigned long phys_initrd_start __initdata = 0;
> +static phys_addr_t phys_initrd_start __initdata = 0;
>  static unsigned long phys_initrd_size __initdata = 0;
>  
>  static int __init early_initrd(char *p)
>  {
> -	unsigned long start, size;
> +	phys_addr_t start;
> +	unsigned long size;
>  	char *endp;
>  
>  	start = memparse(p, &endp);
> @@ -347,14 +348,14 @@ void __init arm_memblock_init(struct meminfo *mi, struct machine_desc *mdesc)
>  #ifdef CONFIG_BLK_DEV_INITRD
>  	if (phys_initrd_size &&
>  	    !memblock_is_region_memory(phys_initrd_start, phys_initrd_size)) {
> -		pr_err("INITRD: 0x%08lx+0x%08lx is not a memory region - disabling initrd\n",
> -		       phys_initrd_start, phys_initrd_size);
> +		pr_err("INITRD: 0x%08llx+0x%08lx is not a memory region - disabling initrd\n",
> +		       (u64)phys_initrd_start, phys_initrd_size);
>  		phys_initrd_start = phys_initrd_size = 0;
>  	}
>  	if (phys_initrd_size &&
>  	    memblock_is_region_reserved(phys_initrd_start, phys_initrd_size)) {
> -		pr_err("INITRD: 0x%08lx+0x%08lx overlaps in-use memory region - disabling initrd\n",
> -		       phys_initrd_start, phys_initrd_size);
> +		pr_err("INITRD: 0x%08llx+0x%08lx overlaps in-use memory region - disabling initrd\n",
> +		       (u64)phys_initrd_start, phys_initrd_size);
>  		phys_initrd_start = phys_initrd_size = 0;
>  	}
>  	if (phys_initrd_size) {
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm()
  2012-08-11  1:24 ` [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
@ 2012-08-12  4:04   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  4:04 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch modifies the switch_mm() processor functions to use phys_addr_t.
> On LPAE systems, we now honor the upper 32-bits of the physical address that
> is being passed in, and program these into TTBR as expected.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> ---
>  arch/arm/include/asm/proc-fns.h |    4 ++--
>  arch/arm/mm/proc-v7-3level.S    |   26 ++++++++++++++++++++++----
>  2 files changed, 24 insertions(+), 6 deletions(-)
> 
> diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
> index f3628fb..75b5f14 100644
> --- a/arch/arm/include/asm/proc-fns.h
> +++ b/arch/arm/include/asm/proc-fns.h
> @@ -60,7 +60,7 @@ extern struct processor {
>  	/*
>  	 * Set the page table
>  	 */
> -	void (*switch_mm)(unsigned long pgd_phys, struct mm_struct *mm);
> +	void (*switch_mm)(phys_addr_t pgd_phys, struct mm_struct *mm);
>  	/*
>  	 * Set a possibly extended PTE.  Non-extended PTEs should
>  	 * ignore 'ext'.
> @@ -82,7 +82,7 @@ extern void cpu_proc_init(void);
>  extern void cpu_proc_fin(void);
>  extern int cpu_do_idle(void);
>  extern void cpu_dcache_clean_area(void *, int);
> -extern void cpu_do_switch_mm(unsigned long pgd_phys, struct mm_struct *mm);
> +extern void cpu_do_switch_mm(phys_addr_t pgd_phys, struct mm_struct *mm);
>  #ifdef CONFIG_ARM_LPAE
>  extern void cpu_set_pte_ext(pte_t *ptep, pte_t pte);
>  #else
> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
> index 8de0f1d..78bd88c 100644
> --- a/arch/arm/mm/proc-v7-3level.S
> +++ b/arch/arm/mm/proc-v7-3level.S
> @@ -39,6 +39,22 @@
>  #define TTB_FLAGS_SMP	(TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
>  #define PMD_FLAGS_SMP	(PMD_SECT_WBWA|PMD_SECT_S)
>  
> +#define rzero	r3
> +#ifndef CONFIG_ARM_LPAE
> +#  define rpgdl	r0
> +#  define rpgdh	rzero
> +#  define rmm	r1
> +#else
> +#  define rmm	r2
> +#ifndef __ARMEB__
> +#  define rpgdl	r0
> +#  define rpgdh	r1
> +#else
> +#  define rpgdl	r1
> +#  define rpgdh	r0
> +#endif
> +#endif

Given proc-v7-3level.S is used only when CONFIG_ARM_LPAE is defined, you 
shouldn't need all the above.

>  /*
>   * cpu_v7_switch_mm(pgd_phys, tsk)
>   *
> @@ -47,10 +63,12 @@
>   */
>  ENTRY(cpu_v7_switch_mm)
>  #ifdef CONFIG_MMU
> -	ldr	r1, [r1, #MM_CONTEXT_ID]	@ get mm->context.id
> -	and	r3, r1, #0xff
> -	mov	r3, r3, lsl #(48 - 32)		@ ASID
> -	mcrr	p15, 0, r0, r3, c2		@ set TTB 0
> +	mov	rzero, #0
> +	ldr	rmm, [rmm, #MM_CONTEXT_ID]	@ get mm->context.id
> +	and	rmm, rmm, #0xff
> +	mov	rmm, rmm, lsl #(48 - 32)	@ ASID
> +	orr	rpgdh, rpgdh, rmm		@ upper 32-bits of pgd phys
> +	mcrr	p15, 0, rpgdl, rpgdh, c2	@ set TTB 0
>  	isb
>  #endif
>  	mov	pc, lr
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers
  2012-08-11  1:24 ` [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
@ 2012-08-12  4:11   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  4:11 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch adds TTBR accessor macros, and modifies cpu_get_pgd() and
> the LPAE version of cpu_set_reserved_ttbr0() to use these instead.
> 
> In the process, we also fix these functions to correctly handle cases
> where the physical address lies beyond the 4G limit of 32-bit addressing.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> ---
>  arch/arm/include/asm/proc-fns.h |   24 +++++++++++++++++++-----
>  arch/arm/mm/context.c           |    9 ++-------
>  2 files changed, 21 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm/include/asm/proc-fns.h b/arch/arm/include/asm/proc-fns.h
> index 75b5f14..24224df 100644
> --- a/arch/arm/include/asm/proc-fns.h
> +++ b/arch/arm/include/asm/proc-fns.h
> @@ -116,13 +116,27 @@ extern void cpu_resume(void);
>  #define cpu_switch_mm(pgd,mm) cpu_do_switch_mm(virt_to_phys(pgd),mm)
>  
>  #ifdef CONFIG_ARM_LPAE
> +
> +#define cpu_get_ttbr(nr)					\
> +	({							\
> +		u64 ttbr;					\
> +		__asm__("mrrc	p15, " #nr ", %Q0, %R0, c2"	\
> +			: "=r" (ttbr)				\
> +			: : "cc");				\
> +		ttbr;						\
> +	})

I don't think you have to clobber the condition code (cc) here.  It has 
been a long while since the ability to pass a condition code inside an 
inline assembly statement was removed from gcc.

Other that that...

Acked-by: Nicolas Pitre <nico@linaro.org>


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations
  2012-08-11  1:24 ` [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
@ 2012-08-12  4:19   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  4:19 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch moves the TTBR1 offset calculation and the T1SZ calculation out
> of the TTB setup assembly code.  This should not affect functionality in
> any way, but improves code readability as well as readability of subsequent
> patches in this series.
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>

Acked-by: Nicolas Pitre <nico@linaro.org>


> ---
>  arch/arm/include/asm/pgtable-3level-hwdef.h |   10 ++++++++++
>  arch/arm/mm/proc-v7-3level.S                |   16 ++++------------
>  2 files changed, 14 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm/include/asm/pgtable-3level-hwdef.h b/arch/arm/include/asm/pgtable-3level-hwdef.h
> index d795282..b501650 100644
> --- a/arch/arm/include/asm/pgtable-3level-hwdef.h
> +++ b/arch/arm/include/asm/pgtable-3level-hwdef.h
> @@ -74,4 +74,14 @@
>  #define PHYS_MASK_SHIFT		(40)
>  #define PHYS_MASK		((1ULL << PHYS_MASK_SHIFT) - 1)
>  
> +#if defined CONFIG_VMSPLIT_2G
> +#define TTBR1_OFFSET	(1 << 4)		/* skip two L1 entries */
> +#elif defined CONFIG_VMSPLIT_3G
> +#define TTBR1_OFFSET	(4096 * (1 + 3))	/* only L2, skip pgd + 3*pmd */
> +#else
> +#define TTBR1_OFFSET	0
> +#endif
> +
> +#define TTBR1_SIZE	(((PAGE_OFFSET >> 30) - 1) << 16)
> +
>  #endif
> diff --git a/arch/arm/mm/proc-v7-3level.S b/arch/arm/mm/proc-v7-3level.S
> index 78bd88c..e28383f 100644
> --- a/arch/arm/mm/proc-v7-3level.S
> +++ b/arch/arm/mm/proc-v7-3level.S
> @@ -137,18 +137,10 @@ ENDPROC(cpu_v7_set_pte_ext)
>  	 * booting secondary CPUs would end up using TTBR1 for the identity
>  	 * mapping set up in TTBR0.
>  	 */
> -	bhi	9001f				@ PHYS_OFFSET > PAGE_OFFSET?
> -	orr	\tmp, \tmp, #(((PAGE_OFFSET >> 30) - 1) << 16) @ TTBCR.T1SZ
> -#if defined CONFIG_VMSPLIT_2G
> -	/* PAGE_OFFSET == 0x80000000, T1SZ == 1 */
> -	add	\ttbr1, \ttbr1, #1 << 4		@ skip two L1 entries
> -#elif defined CONFIG_VMSPLIT_3G
> -	/* PAGE_OFFSET == 0xc0000000, T1SZ == 2 */
> -	add	\ttbr1, \ttbr1, #4096 * (1 + 3)	@ only L2 used, skip pgd+3*pmd
> -#endif
> -	/* CONFIG_VMSPLIT_1G does not need TTBR1 adjustment */
> -9001:	mcr	p15, 0, \tmp, c2, c0, 2		@ TTB control register
> -	mcrr	p15, 1, \ttbr1, \zero, c2	@ load TTBR1
> +	orrls	\tmp, \tmp, #TTBR1_SIZE				@ TTBCR.T1SZ
> +	mcr	p15, 0, \tmp, c2, c0, 2				@ TTBCR
> +	addls	\ttbr1, \ttbr1, #TTBR1_OFFSET
> +	mcrr	p15, 1, \ttbr1, \zero, c2			@ load TTBR1
>  	.endm
>  
>  	__CPUINIT
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks
  2012-08-11  1:24 ` [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
@ 2012-08-12  4:29   ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  4:29 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> This patch modifies the highmem sanity checking code to use physical addresses
> instead.  This change eliminates the wrap-around problems associated with the
> original virtual address based checks, and this simplifies the code a bit.
> 
> The one constraint imposed here is that low physical memory must be mapped in
> a monotonically increasing fashion if there are multiple banks of memory,
> i.e., x < y must => pa(x) < pa(y).
> 
> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>

Acked-by: Nicolas Pitre <nico@linaro.org>


> ---
>  arch/arm/mm/mmu.c |   22 ++++++++++------------
>  1 file changed, 10 insertions(+), 12 deletions(-)
> 
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index 53eeeb8..f764c03 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -895,6 +895,7 @@ phys_addr_t arm_lowmem_limit __initdata = 0;
>  void __init sanity_check_meminfo(void)
>  {
>  	int i, j, highmem = 0;
> +	phys_addr_t vmalloc_limit = __pa(vmalloc_min - 1) + 1;
>  
>  	for (i = 0, j = 0; i < meminfo.nr_banks; i++) {
>  		struct membank *bank = &meminfo.bank[j];
> @@ -904,8 +905,7 @@ void __init sanity_check_meminfo(void)
>  			highmem = 1;
>  
>  #ifdef CONFIG_HIGHMEM
> -		if (__va(bank->start) >= vmalloc_min ||
> -		    __va(bank->start) < (void *)PAGE_OFFSET)
> +		if (bank->start >= vmalloc_limit)
>  			highmem = 1;
>  
>  		bank->highmem = highmem;
> @@ -914,8 +914,8 @@ void __init sanity_check_meminfo(void)
>  		 * Split those memory banks which are partially overlapping
>  		 * the vmalloc area greatly simplifying things later.
>  		 */
> -		if (!highmem && __va(bank->start) < vmalloc_min &&
> -		    bank->size > vmalloc_min - __va(bank->start)) {
> +		if (!highmem && bank->start < vmalloc_limit &&
> +		    bank->size > vmalloc_limit - bank->start) {
>  			if (meminfo.nr_banks >= NR_BANKS) {
>  				printk(KERN_CRIT "NR_BANKS too low, "
>  						 "ignoring high memory\n");
> @@ -924,12 +924,12 @@ void __init sanity_check_meminfo(void)
>  					(meminfo.nr_banks - i) * sizeof(*bank));
>  				meminfo.nr_banks++;
>  				i++;
> -				bank[1].size -= vmalloc_min - __va(bank->start);
> -				bank[1].start = __pa(vmalloc_min - 1) + 1;
> +				bank[1].size -= vmalloc_limit - bank->start;
> +				bank[1].start = vmalloc_limit;
>  				bank[1].highmem = highmem = 1;
>  				j++;
>  			}
> -			bank->size = vmalloc_min - __va(bank->start);
> +			bank->size = vmalloc_limit - bank->start;
>  		}
>  #else
>  		bank->highmem = highmem;
> @@ -949,8 +949,7 @@ void __init sanity_check_meminfo(void)
>  		 * Check whether this memory bank would entirely overlap
>  		 * the vmalloc area.
>  		 */
> -		if (__va(bank->start) >= vmalloc_min ||
> -		    __va(bank->start) < (void *)PAGE_OFFSET) {
> +		if (bank->start >= vmalloc_limit) {
>  			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
>  			       "(vmalloc region overlap).\n",
>  			       (unsigned long long)bank->start,
> @@ -962,9 +961,8 @@ void __init sanity_check_meminfo(void)
>  		 * Check whether this memory bank would partially overlap
>  		 * the vmalloc area.
>  		 */
> -		if (__va(bank->start + bank->size) > vmalloc_min ||
> -		    __va(bank->start + bank->size) < __va(bank->start)) {
> -			unsigned long newsize = vmalloc_min - __va(bank->start);
> +		if (bank->start + bank->size > vmalloc_limit)
> +			unsigned long newsize = vmalloc_limit - bank->start;
>  			printk(KERN_NOTICE "Truncating RAM at %.8llx-%.8llx "
>  			       "to -%.8llx (vmalloc region overlap).\n",
>  			       (unsigned long long)bank->start,
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area
  2012-08-11  1:24 ` [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
@ 2012-08-12  4:36   ` Nicolas Pitre
  2012-09-10 17:43     ` Cyril Chemparathy
  0 siblings, 1 reply; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-12  4:36 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Fri, 10 Aug 2012, Cyril Chemparathy wrote:

> On Keystone platforms, physical memory is entirely outside the 32-bit
> addressible range.  Therefore, the (bank->start > ULONG_MAX) check below marks
> the entire system memory as highmem, and this causes unpleasentness all over.
> 
> This patch eliminates the extra bank start check (against ULONG_MAX) by
> checking bank->start against the physical address corresponding to vmalloc_min
> instead.
> 
> In the process, this patch also cleans up parts of the highmem sanity check
> code by removing what has now become a redundant check for banks that entirely
> overlap with the vmalloc range.

Are you sure of this?  The code that you removed not only checks for 
banks that fall into the vmalloc area, but it also skipp them.  This is 
now lost.

> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> ---
>  arch/arm/mm/mmu.c |   19 +------------------
>  1 file changed, 1 insertion(+), 18 deletions(-)
> 
> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> index f764c03..3d685c6 100644
> --- a/arch/arm/mm/mmu.c
> +++ b/arch/arm/mm/mmu.c
> @@ -901,15 +901,12 @@ void __init sanity_check_meminfo(void)
>  		struct membank *bank = &meminfo.bank[j];
>  		*bank = meminfo.bank[i];
>  
> -		if (bank->start > ULONG_MAX)
> -			highmem = 1;
> -
> -#ifdef CONFIG_HIGHMEM
>  		if (bank->start >= vmalloc_limit)
>  			highmem = 1;
>  
>  		bank->highmem = highmem;
>  
> +#ifdef CONFIG_HIGHMEM
>  		/*
>  		 * Split those memory banks which are partially overlapping
>  		 * the vmalloc area greatly simplifying things later.
> @@ -932,8 +929,6 @@ void __init sanity_check_meminfo(void)
>  			bank->size = vmalloc_limit - bank->start;
>  		}
>  #else
> -		bank->highmem = highmem;
> -
>  		/*
>  		 * Highmem banks not allowed with !CONFIG_HIGHMEM.
>  		 */
> @@ -946,18 +941,6 @@ void __init sanity_check_meminfo(void)
>  		}
>  
>  		/*
> -		 * Check whether this memory bank would entirely overlap
> -		 * the vmalloc area.
> -		 */
> -		if (bank->start >= vmalloc_limit) {
> -			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
> -			       "(vmalloc region overlap).\n",
> -			       (unsigned long long)bank->start,
> -			       (unsigned long long)bank->start + bank->size - 1);
> -			continue;
> -		}
> -
> -		/*
>  		 * Check whether this memory bank would partially overlap
>  		 * the vmalloc area.
>  		 */
> -- 
> 1.7.9.5
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/22] ARM: add self test for runtime patch mechanism
  2012-08-12  2:35   ` Nicolas Pitre
@ 2012-08-12 16:32     ` Cyril Chemparathy
  2012-08-13  3:19       ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-12 16:32 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On 08/11/12 22:35, Nicolas Pitre wrote:
> On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
>
>> This patch adds basic sanity tests to ensure that the instruction patching
>> results in valid instruction encodings.  This is done by verifying the output
>> of the patch process against a vector of assembler generated instructions at
>> init time.
>>
>> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
>> ---
[...]
>> +	__asm__ __volatile__ (
>> +		"	.irp	shift1, 0, 6, 12, 18\n"
>> +		"	.irp	shift2, 0, 1, 2, 3, 4, 5\n"
>> +		"	add     r1, r2, #(0x41 << (\\shift1 + \\shift2))\n"
>> +		"	.endr\n"
>> +		"	.endr\n"
>
>
> Maybe adding a "add r1, r2 #0x81 << 24" here might be a good thing since
> this is the most used case but missing from the above.
>

Indeed.  I've now replaced this with something a bit more extensive. 
Does the following look better?

+struct patch_test_imm8 {
+       u16     imm;
+       u16     shift;
+       u32     insn;
+};
+
+static void __init __used __naked __patch_test_code_imm8(void)
+{
+       __asm__ __volatile__ (
+
+               /* a single test case */
+               "       .macro          test_one, imm, sft\n"
+               "       .hword          \\imm\n"
+               "       .hword          \\sft\n"
+               "       add             r1, r2, #(\\imm << \\sft)\n"
+               "       .endm\n"
+
+               /* a sequence of tests at 'inc' increments of shift */
+               "       .macro          test_seq, imm, sft, max, inc\n"
+               "       test_one        \\imm, \\sft\n"
+               "       .if             \\sft < \\max\n"
+               "       test_seq        \\imm, (\\sft + \\inc), \\max, 
\\inc\n"
+               "       .endif\n"
+               "       .endm\n"
+
+               /* an empty record to mark the end */
+               "       .macro          test_end\n"
+               "       .hword          0, 0\n"
+               "       .word           0\n"
+               "       .endm\n"
+
+               /* finally generate the test sequences */
+               "       test_seq        0x41, 0, 24, 1\n"
+               "       test_seq        0x81, 0, 24, 2\n"
+               "       test_end\n"
+               : : :
+       );
+}
+

[...]
>> +	u32 test_code_addr = (u32)(&__patch_test_code_imm8);
>> +	u32 *test_code = (u32 *)(test_code_addr & ~0x3);
>
> Why this masking?  With Thumb2 you may find functions starting at
> halfword aligned addresses.  Only the LSB (indicating thumb mode) should
> be masked out.
>

Fixed.  Thanks.

Thanks
-- Cyril.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching
  2012-08-12  3:03   ` Nicolas Pitre
@ 2012-08-12 17:34     ` Cyril Chemparathy
  2012-08-13  3:32       ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-12 17:34 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux-kernel, linux-arm-kernel, Arnd Bergmann, Catalin Marinas,
	Grant Likely, Russell King - ARM Linux, Will Deacon

On 08/11/12 23:03, Nicolas Pitre wrote:
> On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
>
>> This patch replaces the original physical offset patching implementation
>> with one that uses the newly added patching framework.  In the process, we now
>> unconditionally initialize the __pv_phys_offset and __pv_offset globals in the
>> head.S code.
>
> This last sentence is now wrong.
>

Removed.

[...]
>> -extern unsigned long __pv_phys_offset;
>> -#define PHYS_OFFSET __pv_phys_offset
[...]
>> +#define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
>
> What was wrong with the former PHYS_OFFSET = __pv_phys_offset ?
>
> If you really want to have it optimized at run time, you could simply
> use your new stub to patch a mov instruction instead of going through
> __virt_to_phys which uses and add on top of a constant.
>

The intent was to optimize out the load(s) on references to PHYS_OFFSET, 
but is it worth it?  If so, we could go with a patched mov (or two) with 
the necessary endian fixups.  If not, we could revert to 
__pv_phys_offset loads as before.

[...]
>>   	s = find_mod_section(hdr, sechdrs, ".runtime.patch.table");
>>   	if (s)
>>   		runtime_patch((void *)s->sh_addr, s->sh_size);
>
> I missed this in the previous patch, but could you fail the module
> loading by returning an error if runtime_patch() fails?  That would take
> care of not accepting modules that might have been compiled with future
> runtime patching extensions that are not yet supported in an earlier
> kernel.
>

Sure.  Thanks.

> You also should remove the MODULE_ARCH_VERMAGIC_P2V definitions now that
> the corresponding code is no longer there.
>

Hmm...

"rt-patch" needs to be in vermagic to prevent modules built against the 
new code from being loaded on older kernels that used the traditional 
patch code.

"p2v" needs to be in there as well, because it should be possible to 
build without PATCH_PHYS_VIRT, but with RUNTIME_PATCH as and when there 
are other users for this.

Thanks
-- Cyril.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 01/22] ARM: add mechanism for late code patching
  2012-08-12  2:22   ` Nicolas Pitre
@ 2012-08-12 18:13     ` Cyril Chemparathy
  0 siblings, 0 replies; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-12 18:13 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On 08/11/12 22:22, Nicolas Pitre wrote:
> On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
>
>> The original phys_to_virt/virt_to_phys patching implementation relied on early
>> patching prior to MMU initialization.  On PAE systems running out of >4G
>> address space, this would have entailed an additional round of patching after
>> switching over to the high address space.
>>
>> The approach implemented here conceptually extends the original PHYS_OFFSET
>> patching implementation with the introduction of "early" patch stubs.  Early
>> patch code is required to be functional out of the box, even before the patch
>> is applied.  This is implemented by inserting functional (but inefficient)
>> load code into the .runtime.patch.code init section.  Having functional code
>> out of the box then allows us to defer the init time patch application until
>> later in the init sequence.
>>
>> In addition to fitting better with our need for physical address-space
>> switch-over, this implementation should be somewhat more extensible by virtue
>> of its more readable (and hackable) C implementation.  This should prove
>> useful for other similar init time specialization needs, especially in light
>> of our multi-platform kernel initiative.
>>
>> This code has been boot tested in both ARM and Thumb-2 modes on an ARMv7
>> (Cortex-A8) device.
>>
>> Note: the obtuse use of stringified symbols in patch_stub() and
>> early_patch_stub() is intentional.  Theoretically this should have been
>> accomplished with formal operands passed into the asm block, but this requires
>> the use of the 'c' modifier for instantiating the long (e.g. .long %c0).
>> However, the 'c' modifier has been found to ICE certain versions of GCC, and
>> therefore we resort to stringified symbols here.
>>
>> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
>
> Reviewed-by: Nicolas Pitre <nico@linaro.org>
>

Thanks.

I've been looking at the compiler emitted code, and had to make a couple 
of changes to keep things streamlined...

[...]
>> +#define early_patch_imm8(insn, to, from, sym, offset)			\
>> +	early_patch_stub(PATCH_IMM8,					\
>> +			 /* code */					\
>> +			 "ldr	%0, =" __stringify(sym + offset) "\n"	\
>> +			 "ldr	%0, [%0]\n"				\
>> +			 insn " %0, %1, %0\n",				\
>> +			 /* patch_data */				\
>> +			 ".long " __stringify(sym + offset) "\n"	\
>> +			 insn " %0, %1, %2\n",				\
>> +			 : "=&r" (to)					\
>> +			 : "r" (from), "I" (__IMM8), "m" (sym)		\
>> +			 : "cc")

First, the "m" operand modifier for "sym" forces GCC to emit code to 
load the address of the symbol into a register.  I've replaced this with 
"i" (&(sym) to make that go away.  With this, the emitted code doesn't 
contain any such unexpected nonsense.

Second, marking the "to" operand as early clobber makes the compiler 
generate horrid register moves around the assembly block, even when it 
has registers to spare.  Simply adding a temporary variable does a much 
much better job, especially since this temporary register is used only 
in the patched-out "early" code.

Thanks
-- Cyril.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-08-12  3:39   ` Nicolas Pitre
@ 2012-08-12 23:27     ` Cyril Chemparathy
  2012-08-13  4:03       ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-08-12 23:27 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On 08/11/12 23:39, Nicolas Pitre wrote:
> On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
>
>> This patch adds support for 64-bit physical addresses in virt_to_phys()
>> patching.  This does not do real 64-bit add/sub, but instead patches in the
>> upper 32-bits of the phys_offset directly into the output of virt_to_phys.
>>
>> There is no corresponding change on the phys_to_virt() side, because
>> computations on the upper 32-bits would be discarded anyway.
>>
>> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
>> ---
>>   arch/arm/include/asm/memory.h |   22 ++++++++++++++++++----
>>   arch/arm/kernel/head.S        |    4 ++++
>>   arch/arm/kernel/setup.c       |    2 +-
>>   3 files changed, 23 insertions(+), 5 deletions(-)
>>
>> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
>> index 81e1714..dc5fbf3 100644
>> --- a/arch/arm/include/asm/memory.h
>> +++ b/arch/arm/include/asm/memory.h
>> @@ -154,14 +154,28 @@
>>   #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
>>
>>   extern unsigned long	__pv_offset;
>> -extern unsigned long	__pv_phys_offset;
>> +extern phys_addr_t	__pv_phys_offset;
>>   #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
>>
>>   static inline phys_addr_t __virt_to_phys(unsigned long x)
>>   {
>> -	unsigned long t;
>> -	early_patch_imm8("add", t, x, __pv_offset, 0);
>> -	return t;
>> +	unsigned long tlo, thi;
>> +
>> +	early_patch_imm8("add", tlo, x, __pv_offset, 0);
>> +
>> +#ifdef CONFIG_ARM_LPAE
>> +	/*
>> +	 * On LPAE, we do not _need_ to do 64-bit arithmetic because the high
>> +	 * order 32 bits are never changed by the phys-virt offset.  We simply
>> +	 * patch in the high order physical address bits instead.
>> +	 */
>> +#ifdef __ARMEB__
>> +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
>> +#else
>> +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
>> +#endif
>> +#endif
>> +	return (u64)tlo | (u64)thi << 32;
>>   }
>
> Hmmm...  I'm afraid this is going to be suboptimal when LPAE is not
> selected.
>

I understand your concern, but I don't see the sub-optimality.  I tested 
the following function with GCC versions 4.3.3 and 4.7.  This is after 
the other changes that I mentioned in my previous email, but with the 
__virt_to_phys() code itself unchanged:

phys_addr_t ____test_virt_to_phys(unsigned long addr)
{
         return __virt_to_phys(addr);
}

The resulting code in both cases looks like:

<____test_virt_to_phys>:
	b       c04f0528
	bx      lr

[the branch of course gets patched to an add]

> First of all, you do not need to cast tlo to a u64 in the return value.
>

True enough.

> Then, I'm not sure if the compiler is smart enough to see that the
> returned value is a phys_addr_t which can be a u32, and in this case the
> (u64)thi << 32 is going to be truncated right away, and therefore there
> is no point in emiting the corresponding instructions.
>

In this case, it appears to be smart enough.  However, I agree that 
relying on compiler smarts is probably not the best thing for us to do.

> Furthermore, if LPAE is not defined, then thi never gets initialized and
> should produce a warning. Did you test compilation of the code with LPAE
> turned off?
>

Sure.  One of our test platforms is non-LPAE.  The compiler does not 
produce warnings on this, and this is consistent across both compiler 
versions.

> I'd prefer something like this where more stuff is validated by the
> compiler:
>
> static inline phys_addr_t __virt_to_phys(unsigned long x)
> {
> 	unsigned long tlo, thi;
> 	phys_addr_t ret;
>
> 	early_patch_imm8("add", tlo, x, __pv_offset, 0);
> 	ret = tlo;
>
> 	if (sizeof(phys_addr_t) > 4) {
> #ifdef __ARMEB__
> 		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
> #else
> 		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
> #endif
> 		ret |= ((u64)thi) << 32;
> 	}
>
> 	return ret);
> }
>
> This should let the compiler optimize things whether LPAE is enabledor
> not while validating both cases.
>

Agreed on the principal, but more below...


I've meanwhile been chasing down another problem - the code generated 
for the LPAE case.  The original code resulted in the following:

<____test_virt_to_phys>:
         mov     r2, #0
         b       c01bc800	# patch: add r1, r0, __pv_offset
         b       c01bc810	# patch: mov r0, __phys_offset_high
         orr     r2, r2, r1
         mov     r3, r0
         mov     r1, r3
         mov     r0, r2
         bx      lr

Yikes! This code does a bunch of futile register shuffling and a 
pointless or, all in the name of generating the result in a 64-bit 
register-pair from the 32-bit halves.

In order to get past this, I tried adding operand qualifiers (R = upper 
32-bits, Q = lower 32-bits) in the patch macros, in the hope that 
treating these as native 64-bit register pairs would eliminate the need 
to shuffle them around after the inline assembly blocks.  This then 
allows us to implement __virt_to_phys() as follows:

static inline phys_addr_t __virt_to_phys(unsigned long x)
{
         phys_addr_t t;

         if (sizeof(t) == 4) {
		t = x;
                 early_patch_imm8("add", t, "", t, __pv_offset, 0);
                 return t;
         }

         /*
          * On LPAE, we do not _need_ to do 64-bit arithmetic because
          * the high order 32 bits are never changed by the phys-virt
          * offset.  We simply patch in the high order physical address
          * bits instead.
          *
          * Note: the mov _must_ be first here.  From the compiler's
          * perspective, this is the initializer for the variable. The
          * mov itself initializes only the upper half. The subsequent
          * add treats t as a read/write operand and initializes the
          * lower half.
          */
#ifdef __ARMEB__
         early_patch_imm8_mov("mov", t, "R", __pv_phys_offset, 0);
#else
         early_patch_imm8_mov("mov", t, "R", __pv_phys_offset, 4);
#endif
         early_patch_imm8("add", t, "Q", x, __pv_offset, 0);

         return t;
}

With this, we get significantly better looking generated code:

<____test_virt_to_phys>:
	b       c01d519c	# patch: mov r3, __phys_offset_high
	b       c01d51ac	# patch: add r2, r0, __phys_offset_high
	mov     r0, r2
	mov     r1, r3
	bx      lr

This is about as far along as I've been able to proceed.  I still 
haven't figured out a way to get it to patch in place without an extra 
register pair.

Overall, this is still a bit too kludgy for my liking.  In particular, 
the read/write operand forces add/sub/... users to initialize the result 
variable.  I am currently leaning towards adding native support for 
64-bit operations in the runtime patch code, instead of having to hack 
around it with 32-bit primitives.  Better ideas, any one?

Thanks
-- Cyril.

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 02/22] ARM: add self test for runtime patch mechanism
  2012-08-12 16:32     ` Cyril Chemparathy
@ 2012-08-13  3:19       ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-13  3:19 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On Sun, 12 Aug 2012, Cyril Chemparathy wrote:

> On 08/11/12 22:35, Nicolas Pitre wrote:
> > On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
> > 
> > > This patch adds basic sanity tests to ensure that the instruction patching
> > > results in valid instruction encodings.  This is done by verifying the
> > > output
> > > of the patch process against a vector of assembler generated instructions
> > > at
> > > init time.
> > > 
> > > Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> > > ---
> [...]
> > > +	__asm__ __volatile__ (
> > > +		"	.irp	shift1, 0, 6, 12, 18\n"
> > > +		"	.irp	shift2, 0, 1, 2, 3, 4, 5\n"
> > > +		"	add     r1, r2, #(0x41 << (\\shift1 + \\shift2))\n"
> > > +		"	.endr\n"
> > > +		"	.endr\n"
> > 
> > 
> > Maybe adding a "add r1, r2 #0x81 << 24" here might be a good thing since
> > this is the most used case but missing from the above.
> > 
> 
> Indeed.  I've now replaced this with something a bit more extensive. Does the
> following look better?
> 
> +struct patch_test_imm8 {
> +       u16     imm;
> +       u16     shift;
> +       u32     insn;
> +};
> +
> +static void __init __used __naked __patch_test_code_imm8(void)
> +{
> +       __asm__ __volatile__ (
> +
> +               /* a single test case */
> +               "       .macro          test_one, imm, sft\n"
> +               "       .hword          \\imm\n"
> +               "       .hword          \\sft\n"
> +               "       add             r1, r2, #(\\imm << \\sft)\n"
> +               "       .endm\n"
> +
> +               /* a sequence of tests at 'inc' increments of shift */
> +               "       .macro          test_seq, imm, sft, max, inc\n"
> +               "       test_one        \\imm, \\sft\n"
> +               "       .if             \\sft < \\max\n"
> +               "       test_seq        \\imm, (\\sft + \\inc), \\max,
> \\inc\n"
> +               "       .endif\n"
> +               "       .endm\n"
> +
> +               /* an empty record to mark the end */
> +               "       .macro          test_end\n"
> +               "       .hword          0, 0\n"
> +               "       .word           0\n"
> +               "       .endm\n"
> +
> +               /* finally generate the test sequences */
> +               "       test_seq        0x41, 0, 24, 1\n"
> +               "       test_seq        0x81, 0, 24, 2\n"
> +               "       test_end\n"
> +               : : :
> +       );
> +}

Yes, this is certainly quite extensive.  :-)


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching
  2012-08-12 17:34     ` Cyril Chemparathy
@ 2012-08-13  3:32       ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-13  3:32 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, Arnd Bergmann, Catalin Marinas,
	Grant Likely, Russell King - ARM Linux, Will Deacon

On Sun, 12 Aug 2012, Cyril Chemparathy wrote:

> On 08/11/12 23:03, Nicolas Pitre wrote:
> > On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
> > 
> > > -extern unsigned long __pv_phys_offset;
> > > -#define PHYS_OFFSET __pv_phys_offset
> [...]
> > > +#define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
> > 
> > What was wrong with the former PHYS_OFFSET = __pv_phys_offset ?
> > 
> > If you really want to have it optimized at run time, you could simply
> > use your new stub to patch a mov instruction instead of going through
> > __virt_to_phys which uses and add on top of a constant.
> > 
> 
> The intent was to optimize out the load(s) on references to PHYS_OFFSET, but
> is it worth it?  If so, we could go with a patched mov (or two) with the
> necessary endian fixups.  If not, we could revert to __pv_phys_offset loads as
> before.

If you want to do better than the load, then you'd better go all the way 
with the patched move.

> > You also should remove the MODULE_ARCH_VERMAGIC_P2V definitions now that
> > the corresponding code is no longer there.
> > 
> 
> Hmm...
> 
> "rt-patch" needs to be in vermagic to prevent modules built against the new
> code from being loaded on older kernels that used the traditional patch code.

Right.

> "p2v" needs to be in there as well, because it should be possible to build
> without PATCH_PHYS_VIRT, but with RUNTIME_PATCH as and when there are other
> users for this.

That doesn't matter if there are other users.  As soon as there is a 
.init.runtime_patch_table that needs to be processed then "rt-patch" 
flags it.  Whether this is used for PATCH_PHYS_VIRT or other purposes is 
irrelevant.

However there isn't any pv_table anymore, so "p2v" should go as there is 
no more code to process those tables if they're ever encountered.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-08-12 23:27     ` Cyril Chemparathy
@ 2012-08-13  4:03       ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-08-13  4:03 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon

On Sun, 12 Aug 2012, Cyril Chemparathy wrote:

> On 08/11/12 23:39, Nicolas Pitre wrote:
> > On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
> > 
> > > This patch adds support for 64-bit physical addresses in virt_to_phys()
> > > patching.  This does not do real 64-bit add/sub, but instead patches in
> > > the
> > > upper 32-bits of the phys_offset directly into the output of virt_to_phys.
> > > 
> > > There is no corresponding change on the phys_to_virt() side, because
> > > computations on the upper 32-bits would be discarded anyway.
> > > 
> > > Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> > > ---
> > >   arch/arm/include/asm/memory.h |   22 ++++++++++++++++++----
> > >   arch/arm/kernel/head.S        |    4 ++++
> > >   arch/arm/kernel/setup.c       |    2 +-
> > >   3 files changed, 23 insertions(+), 5 deletions(-)
> > > 
> > > diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> > > index 81e1714..dc5fbf3 100644
> > > --- a/arch/arm/include/asm/memory.h
> > > +++ b/arch/arm/include/asm/memory.h
> > > @@ -154,14 +154,28 @@
> > >   #ifdef CONFIG_ARM_PATCH_PHYS_VIRT
> > > 
> > >   extern unsigned long	__pv_offset;
> > > -extern unsigned long	__pv_phys_offset;
> > > +extern phys_addr_t	__pv_phys_offset;
> > >   #define PHYS_OFFSET	__virt_to_phys(PAGE_OFFSET)
> > > 
> > >   static inline phys_addr_t __virt_to_phys(unsigned long x)
> > >   {
> > > -	unsigned long t;
> > > -	early_patch_imm8("add", t, x, __pv_offset, 0);
> > > -	return t;
> > > +	unsigned long tlo, thi;
> > > +
> > > +	early_patch_imm8("add", tlo, x, __pv_offset, 0);
> > > +
> > > +#ifdef CONFIG_ARM_LPAE
> > > +	/*
> > > +	 * On LPAE, we do not _need_ to do 64-bit arithmetic because the high
> > > +	 * order 32 bits are never changed by the phys-virt offset.  We simply
> > > +	 * patch in the high order physical address bits instead.
> > > +	 */
> > > +#ifdef __ARMEB__
> > > +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
> > > +#else
> > > +	early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
> > > +#endif
> > > +#endif
> > > +	return (u64)tlo | (u64)thi << 32;
> > >   }
> > 
> > Hmmm...  I'm afraid this is going to be suboptimal when LPAE is not
> > selected.
> > 
> 
> I understand your concern, but I don't see the sub-optimality.  I tested the
> following function with GCC versions 4.3.3 and 4.7.  This is after the other
> changes that I mentioned in my previous email, but with the __virt_to_phys()
> code itself unchanged:
> 
> phys_addr_t ____test_virt_to_phys(unsigned long addr)
> {
>         return __virt_to_phys(addr);
> }
> 
> The resulting code in both cases looks like:
> 
> <____test_virt_to_phys>:
> 	b       c04f0528
> 	bx      lr
> 
> [the branch of course gets patched to an add]

OK.  Please add such information and results in your commit log.

> > First of all, you do not need to cast tlo to a u64 in the return value.
> > 
> 
> True enough.
> 
> > Then, I'm not sure if the compiler is smart enough to see that the
> > returned value is a phys_addr_t which can be a u32, and in this case the
> > (u64)thi << 32 is going to be truncated right away, and therefore there
> > is no point in emiting the corresponding instructions.
> > 
> 
> In this case, it appears to be smart enough.  However, I agree that relying on
> compiler smarts is probably not the best thing for us to do.

Well, we do rely on a lot of compiler smarts in the kernel.  As long as 
sufficiently old compiler versions do get it right then it should be 
fine.

> > Furthermore, if LPAE is not defined, then thi never gets initialized and
> > should produce a warning. Did you test compilation of the code with LPAE
> > turned off?
> > 
> 
> Sure.  One of our test platforms is non-LPAE.  The compiler does not produce
> warnings on this, and this is consistent across both compiler versions.

That is odd.  I still prefer my version nevertheless so to avoid this 
potential issue in the future.

> > I'd prefer something like this where more stuff is validated by the
> > compiler:
> > 
> > static inline phys_addr_t __virt_to_phys(unsigned long x)
> > {
> > 	unsigned long tlo, thi;
> > 	phys_addr_t ret;
> > 
> > 	early_patch_imm8("add", tlo, x, __pv_offset, 0);
> > 	ret = tlo;
> > 
> > 	if (sizeof(phys_addr_t) > 4) {
> > #ifdef __ARMEB__
> > 		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 0);
> > #else
> > 		early_patch_imm8_mov("mov", thi, __pv_phys_offset, 4);
> > #endif
> > 		ret |= ((u64)thi) << 32;
> > 	}
> > 
> > 	return ret);
> > }
> > 
> > This should let the compiler optimize things whether LPAE is enabledor
> > not while validating both cases.
> > 
> 
> Agreed on the principal, but more below...
> 
> 
> I've meanwhile been chasing down another problem - the code generated for the
> LPAE case.  The original code resulted in the following:
> 
> <____test_virt_to_phys>:
>         mov     r2, #0
>         b       c01bc800	# patch: add r1, r0, __pv_offset
>         b       c01bc810	# patch: mov r0, __phys_offset_high
>         orr     r2, r2, r1
>         mov     r3, r0
>         mov     r1, r3
>         mov     r0, r2
>         bx      lr
> 
> Yikes! This code does a bunch of futile register shuffling and a pointless or,
> all in the name of generating the result in a 64-bit register-pair from the
> 32-bit halves.
> 
> In order to get past this, I tried adding operand qualifiers (R = upper
> 32-bits, Q = lower 32-bits) in the patch macros, in the hope that treating
> these as native 64-bit register pairs would eliminate the need to shuffle them
> around after the inline assembly blocks.  This then allows us to implement
> __virt_to_phys() as follows:
> 
> static inline phys_addr_t __virt_to_phys(unsigned long x)
> {
>         phys_addr_t t;
> 
>         if (sizeof(t) == 4) {
> 		t = x;
>                 early_patch_imm8("add", t, "", t, __pv_offset, 0);
>                 return t;
>         }
> 
>         /*
>          * On LPAE, we do not _need_ to do 64-bit arithmetic because
>          * the high order 32 bits are never changed by the phys-virt
>          * offset.  We simply patch in the high order physical address
>          * bits instead.
>          *
>          * Note: the mov _must_ be first here.  From the compiler's
>          * perspective, this is the initializer for the variable. The
>          * mov itself initializes only the upper half. The subsequent
>          * add treats t as a read/write operand and initializes the
>          * lower half.
>          */
> #ifdef __ARMEB__
>         early_patch_imm8_mov("mov", t, "R", __pv_phys_offset, 0);
> #else
>         early_patch_imm8_mov("mov", t, "R", __pv_phys_offset, 4);
> #endif
>         early_patch_imm8("add", t, "Q", x, __pv_offset, 0);
> 
>         return t;
> }
> 
> With this, we get significantly better looking generated code:
> 
> <____test_virt_to_phys>:
> 	b       c01d519c	# patch: mov r3, __phys_offset_high
> 	b       c01d51ac	# patch: add r2, r0, __phys_offset_high
> 	mov     r0, r2
> 	mov     r1, r3
> 	bx      lr
> 
> This is about as far along as I've been able to proceed.  I still haven't
> figured out a way to get it to patch in place without an extra register pair.
> 
> Overall, this is still a bit too kludgy for my liking.  In particular, the
> read/write operand forces add/sub/... users to initialize the result variable.
> I am currently leaning towards adding native support for 64-bit operations in
> the runtime patch code, instead of having to hack around it with 32-bit
> primitives.  Better ideas, any one?

The best I've come up with is this:

//typedef unsigned long phys_addr_t;
typedef unsigned long long phys_addr_t;

phys_addr_t __virt_to_phys(unsigned long v)
{
	phys_addr_t p;

	if (sizeof(phys_addr_t) > 4) {
		asm ("add %Q0, %1, #PV_OFFSET" : "=r" (p) : "r" (v));
		asm ("mov %R0, #PHYS_HIGHBITS" : "+r" (p));
	} else {
		asm ("add %0, %1, #PV_OFFSET" : "=r" (p) : "r" (v));
	}

	return p;
}

The add is done first as this reduce the life span of the v variable.  
Because p is listed as an early clobber, then in theory the register 
holding v could be used to store the low part of p right away.  If you 
put the mov first then you can't do that especially on big endian.

It seems that there is no clean way to combine the LPAE and non LPAE 
cases.


Nicolas

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area
  2012-08-12  4:36   ` Nicolas Pitre
@ 2012-09-10 17:43     ` Cyril Chemparathy
  2012-09-10 18:07       ` Nicolas Pitre
  0 siblings, 1 reply; 44+ messages in thread
From: Cyril Chemparathy @ 2012-09-10 17:43 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On 8/12/2012 12:36 AM, Nicolas Pitre wrote:
> On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
>
>> On Keystone platforms, physical memory is entirely outside the 32-bit
>> addressible range.  Therefore, the (bank->start > ULONG_MAX) check below marks
>> the entire system memory as highmem, and this causes unpleasentness all over.
>>
>> This patch eliminates the extra bank start check (against ULONG_MAX) by
>> checking bank->start against the physical address corresponding to vmalloc_min
>> instead.
>>
>> In the process, this patch also cleans up parts of the highmem sanity check
>> code by removing what has now become a redundant check for banks that entirely
>> overlap with the vmalloc range.
>
> Are you sure of this?  The code that you removed not only checks for
> banks that fall into the vmalloc area, but it also skipp them.  This is
> now lost.
>

I almost missed out on this email...

The check is not quite lost, we still have the following in the 
!CONFIG_HIGHMEM block:

	if (highmem) {
		printk(...);
		continue;
	}

The change is that highmem is now set outside the #ifdef when 
(bank->start >= vmalloc_limit), and therefore the check is truly redundant.

>> Signed-off-by: Cyril Chemparathy <cyril@ti.com>
>> Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
>> ---
>>   arch/arm/mm/mmu.c |   19 +------------------
>>   1 file changed, 1 insertion(+), 18 deletions(-)
>>
>> diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
>> index f764c03..3d685c6 100644
>> --- a/arch/arm/mm/mmu.c
>> +++ b/arch/arm/mm/mmu.c
>> @@ -901,15 +901,12 @@ void __init sanity_check_meminfo(void)
>>   		struct membank *bank = &meminfo.bank[j];
>>   		*bank = meminfo.bank[i];
>>
>> -		if (bank->start > ULONG_MAX)
>> -			highmem = 1;
>> -
>> -#ifdef CONFIG_HIGHMEM
>>   		if (bank->start >= vmalloc_limit)
>>   			highmem = 1;
>>
>>   		bank->highmem = highmem;
>>
>> +#ifdef CONFIG_HIGHMEM
>>   		/*
>>   		 * Split those memory banks which are partially overlapping
>>   		 * the vmalloc area greatly simplifying things later.
>> @@ -932,8 +929,6 @@ void __init sanity_check_meminfo(void)
>>   			bank->size = vmalloc_limit - bank->start;
>>   		}
>>   #else
>> -		bank->highmem = highmem;
>> -
>>   		/*
>>   		 * Highmem banks not allowed with !CONFIG_HIGHMEM.
>>   		 */
>> @@ -946,18 +941,6 @@ void __init sanity_check_meminfo(void)
>>   		}
>>
>>   		/*
>> -		 * Check whether this memory bank would entirely overlap
>> -		 * the vmalloc area.
>> -		 */
>> -		if (bank->start >= vmalloc_limit) {
>> -			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
>> -			       "(vmalloc region overlap).\n",
>> -			       (unsigned long long)bank->start,
>> -			       (unsigned long long)bank->start + bank->size - 1);
>> -			continue;
>> -		}
>> -
>> -		/*
>>   		 * Check whether this memory bank would partially overlap
>>   		 * the vmalloc area.
>>   		 */
>> --
>> 1.7.9.5
>>

-- 
Thanks
- Cyril

^ permalink raw reply	[flat|nested] 44+ messages in thread

* Re: [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area
  2012-09-10 17:43     ` Cyril Chemparathy
@ 2012-09-10 18:07       ` Nicolas Pitre
  0 siblings, 0 replies; 44+ messages in thread
From: Nicolas Pitre @ 2012-09-10 18:07 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-kernel, linux-arm-kernel, arnd, catalin.marinas,
	grant.likely, linux, will.deacon, Vitaly Andrianov

On Mon, 10 Sep 2012, Cyril Chemparathy wrote:

> On 8/12/2012 12:36 AM, Nicolas Pitre wrote:
> > On Fri, 10 Aug 2012, Cyril Chemparathy wrote:
> > 
> > > On Keystone platforms, physical memory is entirely outside the 32-bit
> > > addressible range.  Therefore, the (bank->start > ULONG_MAX) check below
> > > marks
> > > the entire system memory as highmem, and this causes unpleasentness all
> > > over.
> > > 
> > > This patch eliminates the extra bank start check (against ULONG_MAX) by
> > > checking bank->start against the physical address corresponding to
> > > vmalloc_min
> > > instead.
> > > 
> > > In the process, this patch also cleans up parts of the highmem sanity
> > > check
> > > code by removing what has now become a redundant check for banks that
> > > entirely
> > > overlap with the vmalloc range.
> > 
> > Are you sure of this?  The code that you removed not only checks for
> > banks that fall into the vmalloc area, but it also skipp them.  This is
> > now lost.
> > 
> 
> I almost missed out on this email...
> 
> The check is not quite lost, we still have the following in the
> !CONFIG_HIGHMEM block:
> 
> 	if (highmem) {
> 		printk(...);
> 		continue;
> 	}
> 
> The change is that highmem is now set outside the #ifdef when (bank->start >=
> vmalloc_limit), and therefore the check is truly redundant.

OK.

Acked-by: Nicolas Pitre <nico@linaro.org>



> 
> > > Signed-off-by: Cyril Chemparathy <cyril@ti.com>
> > > Signed-off-by: Vitaly Andrianov <vitalya@ti.com>
> > > ---
> > >   arch/arm/mm/mmu.c |   19 +------------------
> > >   1 file changed, 1 insertion(+), 18 deletions(-)
> > > 
> > > diff --git a/arch/arm/mm/mmu.c b/arch/arm/mm/mmu.c
> > > index f764c03..3d685c6 100644
> > > --- a/arch/arm/mm/mmu.c
> > > +++ b/arch/arm/mm/mmu.c
> > > @@ -901,15 +901,12 @@ void __init sanity_check_meminfo(void)
> > >   		struct membank *bank = &meminfo.bank[j];
> > >   		*bank = meminfo.bank[i];
> > > 
> > > -		if (bank->start > ULONG_MAX)
> > > -			highmem = 1;
> > > -
> > > -#ifdef CONFIG_HIGHMEM
> > >   		if (bank->start >= vmalloc_limit)
> > >   			highmem = 1;
> > > 
> > >   		bank->highmem = highmem;
> > > 
> > > +#ifdef CONFIG_HIGHMEM
> > >   		/*
> > >   		 * Split those memory banks which are partially overlapping
> > >   		 * the vmalloc area greatly simplifying things later.
> > > @@ -932,8 +929,6 @@ void __init sanity_check_meminfo(void)
> > >   			bank->size = vmalloc_limit - bank->start;
> > >   		}
> > >   #else
> > > -		bank->highmem = highmem;
> > > -
> > >   		/*
> > >   		 * Highmem banks not allowed with !CONFIG_HIGHMEM.
> > >   		 */
> > > @@ -946,18 +941,6 @@ void __init sanity_check_meminfo(void)
> > >   		}
> > > 
> > >   		/*
> > > -		 * Check whether this memory bank would entirely overlap
> > > -		 * the vmalloc area.
> > > -		 */
> > > -		if (bank->start >= vmalloc_limit) {
> > > -			printk(KERN_NOTICE "Ignoring RAM at %.8llx-%.8llx "
> > > -			       "(vmalloc region overlap).\n",
> > > -			       (unsigned long long)bank->start,
> > > -			       (unsigned long long)bank->start + bank->size -
> > > 1);
> > > -			continue;
> > > -		}
> > > -
> > > -		/*
> > >   		 * Check whether this memory bank would partially overlap
> > >   		 * the vmalloc area.
> > >   		 */
> > > --
> > > 1.7.9.5
> > > 
> 
> -- 
> Thanks
> - Cyril
> 

^ permalink raw reply	[flat|nested] 44+ messages in thread

end of thread, other threads:[~2012-09-10 18:07 UTC | newest]

Thread overview: 44+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-08-11  1:24 [PATCH v2 00/22] Introducing the TI Keystone platform Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 01/22] ARM: add mechanism for late code patching Cyril Chemparathy
2012-08-12  2:22   ` Nicolas Pitre
2012-08-12 18:13     ` Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 02/22] ARM: add self test for runtime patch mechanism Cyril Chemparathy
2012-08-12  2:35   ` Nicolas Pitre
2012-08-12 16:32     ` Cyril Chemparathy
2012-08-13  3:19       ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 03/22] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
2012-08-12  3:03   ` Nicolas Pitre
2012-08-12 17:34     ` Cyril Chemparathy
2012-08-13  3:32       ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 04/22] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
2012-08-12  3:04   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 05/22] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
2012-08-12  3:39   ` Nicolas Pitre
2012-08-12 23:27     ` Cyril Chemparathy
2012-08-13  4:03       ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 06/22] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
2012-08-12  3:57   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 07/22] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 08/22] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 09/22] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
2012-08-12  3:58   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 10/22] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
2012-08-12  4:04   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 11/22] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
2012-08-12  4:11   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 12/22] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 13/22] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
2012-08-12  4:19   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 14/22] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
2012-08-11  1:24 ` [PATCH v2 15/22] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
2012-08-12  4:29   ` Nicolas Pitre
2012-08-11  1:24 ` [PATCH v2 16/22] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
2012-08-12  4:36   ` Nicolas Pitre
2012-09-10 17:43     ` Cyril Chemparathy
2012-09-10 18:07       ` Nicolas Pitre
2012-08-11  1:25 ` [PATCH v2 17/22] ARM: mm: clean up membank size limit checks Cyril Chemparathy
2012-08-11  1:25 ` [PATCH v2 18/22] ARM: add virt_to_idmap for interconnect aliasing Cyril Chemparathy
2012-08-11  1:25 ` [PATCH v2 19/22] ARM: recreate kernel mappings in early_paging_init() Cyril Chemparathy
2012-08-11  1:25 ` [RFC v2 20/22] ARM: keystone: introducing TI Keystone platform Cyril Chemparathy
2012-08-11  1:25 ` [RFC v2 21/22] ARM: keystone: enable SMP on Keystone machines Cyril Chemparathy
2012-08-11  1:25 ` [RFC v2 22/22] ARM: keystone: add switch over to high physical address range Cyril Chemparathy

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).