linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone
@ 2012-09-21 15:55 Cyril Chemparathy
  2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
                   ` (16 more replies)
  0 siblings, 17 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:55 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

This series is a repost of the LPAE related changes in preparation for the
introduction of the Keystone sub-architecture.  Earlier postings of this
series can be found at [1], [2], and [3].

I would very much appreciate feedback and/or next steps towards including
these in linux-next.

These patches are also available in git:
git://git.kernel.org/pub/scm/linux/kernel/git/cchemparathy/linux-keystone.git upstream/keystone-lpae-v3

[1] http://comments.gmane.org/gmane.linux.kernel/1341497
[2] http://comments.gmane.org/gmane.linux.kernel/1332069
[3] http://comments.gmane.org/gmane.linux.kernel/1356716

Series changelog:

(01/22) ARM: add mechanism for late code patching
  (v3)	ability to patch multiple sequential instructions with the IMM8 patch
	type
  (v3)	error handling at module patch time
  (v3)	reuse __patch_text() from kprobes code
  (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
  (v3)	added tests for both even and odd shifts of immediate values
  (v2)	added init-time tests to verify instruction encoding

(03/22) ARM: use late patch framework for phys-virt patching
  (v3)	fixed commit description for unconditional init of __pv_* symbols
  (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
  (v3)	unchanged from v2
  (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
  (v3)	added explicit patch stub for 64-bit to clean up compiler generated
	code, both 64-bit and 32-bit cases generate optimal code with this
  (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()
  (v3)	unchanged from v2
  (v2)	unchanged from v1

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

(10/22) ARM: LPAE: use phys_addr_t in switch_mm()
  (v3)	remove unnecessary handling for !LPAE in proc-v7-3level
  (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
  (v3)	remove unnecessary condition code clobber
  (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
  (v3)	unchanged from v2
  (v2)	unchanged from v1

(14/22) ARM: LPAE: accomodate >32-bit addresses for page table base
  (v3)	unchanged from v2
  (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
  (v3)	unchanged from v2
  (v2)	unchanged from v1


Cyril Chemparathy (14):
  ARM: add mechanism for late code patching
  ARM: add self test for runtime patch mechanism
  ARM: use late patch framework for phys-virt patching
  ARM: LPAE: use phys_addr_t on virt <--> phys conversion
  ARM: LPAE: support 64-bit virt_to_phys patching
  ARM: LPAE: use signed arithmetic for mask definitions
  ARM: LPAE: use phys_addr_t in switch_mm()
  ARM: LPAE: use 64-bit accessors for TTBR registers
  ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem
  ARM: LPAE: factor out T1SZ and TTBR1 computations
  ARM: LPAE: accomodate >32-bit addresses for page table base
  ARM: mm: use physical addresses in highmem sanity checks
  ARM: mm: cleanup checks for membank overlap with vmalloc area
  ARM: mm: clean up membank size limit checks

Vitaly Andrianov (3):
  ARM: LPAE: use phys_addr_t in alloc_init_pud()
  ARM: LPAE: use phys_addr_t in free_memmap()
  ARM: LPAE: use phys_addr_t for initrd location and size

 arch/arm/Kconfig                            |   16 ++
 arch/arm/include/asm/memory.h               |  101 +++++++---
 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        |  208 +++++++++++++++++++++
 arch/arm/kernel/Makefile                    |    1 +
 arch/arm/kernel/armksyms.c                  |    4 -
 arch/arm/kernel/head.S                      |  107 +++--------
 arch/arm/kernel/module.c                    |   14 +-
 arch/arm/kernel/runtime-patch.c             |  268 +++++++++++++++++++++++++++
 arch/arm/kernel/setup.c                     |   15 ++
 arch/arm/kernel/smp.c                       |   11 +-
 arch/arm/kernel/vmlinux.lds.S               |   13 +-
 arch/arm/mm/context.c                       |    9 +-
 arch/arm/mm/init.c                          |   19 +-
 arch/arm/mm/mmu.c                           |   49 ++---
 arch/arm/mm/proc-v7-3level.S                |   41 ++--
 20 files changed, 728 insertions(+), 201 deletions(-)
 create mode 100644 arch/arm/include/asm/runtime-patch.h
 create mode 100644 arch/arm/kernel/runtime-patch.c

-- 
1.7.9.5


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

* [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
@ 2012-09-21 15:55 ` Cyril Chemparathy
  2012-09-22 15:10   ` Nicolas Pitre
  2012-09-24 12:06   ` Dave Martin
  2012-09-21 15:56 ` [PATCH v3 RESEND 02/17] ARM: add self test for runtime patch mechanism Cyril Chemparathy
                   ` (15 subsequent siblings)
  16 siblings, 2 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:55 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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>
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 |  208 ++++++++++++++++++++++++++++++++++
 arch/arm/kernel/Makefile             |    1 +
 arch/arm/kernel/module.c             |    9 +-
 arch/arm/kernel/runtime-patch.c      |  193 +++++++++++++++++++++++++++++++
 arch/arm/kernel/setup.c              |    3 +
 arch/arm/kernel/vmlinux.lds.S        |   10 ++
 8 files changed, 433 insertions(+), 1 deletion(-)
 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 2f88d8d..98a3a1a 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -60,6 +60,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..366444d
--- /dev/null
+++ b/arch/arm/include/asm/runtime-patch.h
@@ -0,0 +1,208 @@
+/*
+ * 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_IMM8		0x0001
+struct patch_info_imm8 {
+	u32		*imm;
+	u32		 insn;
+};
+
+#define patch_next(p)	((void *)(p) + sizeof(*(p)) + (p)->data_size)
+#define patch_data(p)	((void *)&(p)->data[0])
+
+#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, pad, patch_data, ...)		\
+	__asm__("@ patch stub\n"					\
+		"1:\n"							\
+		"	b	6f\n"					\
+		"	.fill	" __stringify(pad) ", 1, 0\n"		\
+		"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"					\
+		"	.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, _ofs)			\
+	patch_stub(							\
+		/* type */						\
+			PATCH_IMM8,					\
+		/* code */						\
+			_insn "	%[to], %[from], %[imm]\n",		\
+		/* patch_data */					\
+			".long " __stringify(_sym + _ofs) "\n"		\
+			_insn "	%[to], %[from], %[imm]\n",		\
+		/* operands */						\
+			: [to]	 "=r" (_to)				\
+			: [from] "r"  (_from),				\
+			  [imm]	 "I"  (__IMM8),				\
+				 "i"  (&(_sym))				\
+			: "cc")
+
+/*
+ * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
+ */
+#define patch_imm8_mov(_insn, _to, _sym, _ofs)				\
+	patch_stub(							\
+		/* type */						\
+			PATCH_IMM8,					\
+		/* code */						\
+			_insn "	%[to], %[imm]\n",			\
+		/* patch_data */					\
+			".long " __stringify(_sym + _ofs) "\n"		\
+			_insn "	%[to], %[imm]\n",			\
+		/* operands */						\
+			: [to]	"=r" (_to)				\
+			: [imm]	"I"  (__IMM8),				\
+				"i"  (&(_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, _ofs)			\
+do {									\
+	unsigned long __tmp;						\
+	early_patch_stub(						\
+		/* type */						\
+			PATCH_IMM8,					\
+		/* code */						\
+			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\
+			"ldr	%[tmp], [%[tmp]]\n"			\
+			_insn "	%[to], %[from], %[tmp]\n",		\
+		/* pad */						\
+			0,						\
+		/* patch_data */					\
+			".long " __stringify(_sym + _ofs) "\n"		\
+			_insn "	%[to], %[from], %[imm]\n",		\
+		/* operands */						\
+			: [to]	 "=r"  (_to),				\
+			  [tmp]	 "=&r" (__tmp)				\
+			: [from] "r"   (_from),				\
+			  [imm]	 "I"   (__IMM8),			\
+				 "i"   (&(_sym))			\
+			: "cc");					\
+} while (0)
+
+#define early_patch_imm8_mov(_insn, _to, _sym, _ofs)			\
+do {									\
+	unsigned long __tmp;						\
+	early_patch_stub(						\
+		/* type */						\
+			PATCH_IMM8					\
+		/* code */						\
+			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\
+			"ldr	%[tmp], [%[tmp]]\n"			\
+			_insn "	%[to], %[tmp]\n",			\
+		/* pad */						\
+			0,						\
+		/* patch_data */					\
+			".long " __stringify(_sym + _ofs) "\n"		\
+			_insn " %[to], %[imm]\n",			\
+		/* operands */						\
+			: [to]	"=r"  (_to),				\
+			  [tmp]	"=&r" (__tmp)				\
+			: [imm]	"I"   (__IMM8),				\
+				"i"   (&(_sym))				\
+			: "cc");					\
+} while (0)
+
+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..0b16b94 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 patch.o
 
 extra-y := $(head-y) vmlinux.lds
diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
index 1e9be5d..10a2922 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
 /*
@@ -276,7 +277,7 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
 	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
 	const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
 	struct mod_unwind_map maps[ARM_SEC_MAX];
-	int i;
+	int i, err;
 
 	memset(maps, 0, sizeof(maps));
 
@@ -321,6 +322,12 @@ 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) {
+		err = runtime_patch((void *)s->sh_addr, s->sh_size);
+		if (err)
+			return err;
+	}
 	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..28a6367
--- /dev/null
+++ b/arch/arm/kernel/runtime-patch.c
@@ -0,0 +1,193 @@
+/*
+ * 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>
+
+#include "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;
+
+	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;
+
+	return 0;
+}
+
+#endif	/* CONFIG_THUMB2_KERNEL */
+
+static int apply_patch_imm8(const struct patch_info *p)
+{
+	u32 *insn_ptr = p->insn, ninsn;
+	int count = p->insn_size / sizeof(u32);
+	const struct patch_info_imm8 *info;
+	int err;
+
+
+	if (count <= 0 || p->data_size != count * sizeof(*info)) {
+		pr_err("patch: bad patch, insn size %d, data size %d\n",
+		       p->insn_size, p->data_size);
+		return -EINVAL;
+	}
+
+	for (info = patch_data(p); count; count--, info++, insn_ptr++) {
+		err = do_patch_imm8(info->insn, *info->imm, &ninsn);
+		if (err)
+			return err;
+		__patch_text(insn_ptr, ninsn);
+	}
+
+
+	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 err = -EINVAL;
+
+		if (p->type == PATCH_IMM8)
+			err = apply_patch_imm8(p);
+		if (err)
+			return err;
+	}
+	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] 29+ messages in thread

* [PATCH v3 RESEND 02/17] ARM: add self test for runtime patch mechanism
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
  2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 03/17] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
                   ` (14 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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 |   75 +++++++++++++++++++++++++++++++++++++++
 2 files changed, 87 insertions(+)

diff --git a/arch/arm/Kconfig b/arch/arm/Kconfig
index 98a3a1a..5bfaa20 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -205,6 +205,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 28a6367..0be9ef3 100644
--- a/arch/arm/kernel/runtime-patch.c
+++ b/arch/arm/kernel/runtime-patch.c
@@ -168,6 +168,78 @@ static int apply_patch_imm8(const struct patch_info *p)
 	return 0;
 }
 
+#ifdef CONFIG_ARM_RUNTIME_PATCH_TEST
+
+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"
+		: : : "r1", "r2", "cc");
+}
+
+static void __init test_patch_imm8(void)
+{
+	u32 test_code_addr = (u32)(&__patch_test_code_imm8);
+	struct patch_test_imm8 *test = (void *)(test_code_addr & ~1);
+	u32 ninsn, insn, patched_insn;
+	int i, err;
+
+	insn = test[0].insn;
+	for (i = 0; test[i].insn; i++) {
+		err = do_patch_imm8(insn, test[i].imm << test[i].shift, &ninsn);
+		__patch_text(&patched_insn, ninsn);
+
+		if (err) {
+			pr_err("rtpatch imm8: failed at imm %x, shift %d\n",
+			       test[i].imm, test[i].shift);
+		} else if (patched_insn != test[i].insn) {
+			pr_err("rtpatch imm8: failed, need %x got %x\n",
+			       test[i].insn, patched_insn);
+		} else {
+			pr_debug("rtpatch imm8: imm %x, shift %d, %x -> %x\n",
+				 test[i].imm, test[i].shift, insn,
+				 patched_insn);
+		}
+	}
+}
+
+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);
@@ -189,5 +261,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] 29+ messages in thread

* [PATCH v3 RESEND 03/17] ARM: use late patch framework for phys-virt patching
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
  2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 02/17] ARM: add self test for runtime patch mechanism Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 04/17] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
                   ` (13 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

This patch replaces the original physical offset patching implementation
with one that uses the newly added patching framework.

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 5bfaa20..0a92735 100644
--- a/arch/arm/Kconfig
+++ b/arch/arm/Kconfig
@@ -193,6 +193,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 5f6ddcc..c88d98c 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 10a2922..021a940 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) {
 		err = 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] 29+ messages in thread

* [PATCH v3 RESEND 04/17] ARM: LPAE: use phys_addr_t on virt <--> phys conversion
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (2 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 03/17] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
                   ` (12 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 c88d98c..88ca206 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
 #endif /* __ASSEMBLY__ */
@@ -210,14 +220,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] 29+ messages in thread

* [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (3 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 04/17] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-22 15:24   ` Nicolas Pitre
  2012-09-24 16:31   ` Dave Martin
  2012-09-21 15:56 ` [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
                   ` (11 subsequent siblings)
  16 siblings, 2 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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 |   38 ++++++++++++++++++++++++++++++++++++--
 arch/arm/kernel/head.S        |    4 ++++
 arch/arm/kernel/setup.c       |    2 +-
 3 files changed, 41 insertions(+), 3 deletions(-)

diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
index 88ca206..f3e8f88 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -154,13 +154,47 @@
 #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;
+	phys_addr_t t;
+
+#ifndef CONFIG_ARM_LPAE
 	early_patch_imm8("add", t, x, __pv_offset, 0);
+#else
+	unsigned long __tmp;
+
+#ifndef __ARMEB__
+#define PV_PHYS_HIGH	"(__pv_phys_offset + 4)"
+#else
+#define PV_PHYS_HIGH	"__pv_phys_offset"
+#endif
+
+	early_patch_stub(
+	/* type */		PATCH_IMM8,
+	/* code */
+		"ldr		%[tmp], =__pv_offset\n"
+		"ldr		%[tmp], [%[tmp]]\n"
+		"add		%Q[to], %[from], %[tmp]\n"
+		"ldr		%[tmp], =" PV_PHYS_HIGH "\n"
+		"ldr		%[tmp], [%[tmp]]\n"
+		"mov		%R[to], %[tmp]\n",
+	/* pad */		4,
+	/* patch_data */
+		".long		__pv_offset\n"
+		"add		%Q[to], %[from], %[imm]\n"
+		".long	"	PV_PHYS_HIGH "\n"
+		"mov		%R[to], %[imm]\n",
+	/* operands */
+		: [to]	 "=r"	(t),
+		  [tmp]	 "=&r"	(__tmp)
+		: [from] "r"	(x),
+		  [imm]	 "I"	(__IMM8),
+			 "i"	(&__pv_offset),
+			 "i"	(&__pv_phys_offset));
+#endif
 	return t;
 }
 
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] 29+ messages in thread

* [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (4 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-24 13:54   ` Russell King - ARM Linux
  2012-09-21 15:56 ` [PATCH v3 RESEND 07/17] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
                   ` (10 subsequent siblings)
  16 siblings, 1 reply; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 related	[flat|nested] 29+ messages in thread

* [PATCH v3 RESEND 07/17] ARM: LPAE: use phys_addr_t in alloc_init_pud()
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (5 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 08/17] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
                   ` (9 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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 c2fa21d..8db7c74 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] 29+ messages in thread

* [PATCH v3 RESEND 08/17] ARM: LPAE: use phys_addr_t in free_memmap()
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (6 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 07/17] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
                   ` (8 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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] 29+ messages in thread

* [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (7 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 08/17] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-24 13:38   ` Russell King - ARM Linux
  2012-09-21 15:56 ` [PATCH v3 RESEND 10/17] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
                   ` (7 subsequent siblings)
  16 siblings, 1 reply; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, 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>
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 related	[flat|nested] 29+ messages in thread

* [PATCH v3 RESEND 10/17] ARM: LPAE: use phys_addr_t in switch_mm()
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (8 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 11/17] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
                   ` (6 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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    |   17 +++++++++++++----
 2 files changed, 15 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..c4f4251 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -39,6 +39,14 @@
 #define TTB_FLAGS_SMP	(TTB_IRGN_WBWA|TTB_S|TTB_RGN_OC_WBWA)
 #define PMD_FLAGS_SMP	(PMD_SECT_WBWA|PMD_SECT_S)
 
+#ifndef __ARMEB__
+#  define rpgdl	r0
+#  define rpgdh	r1
+#else
+#  define rpgdl	r1
+#  define rpgdh	r0
+#endif
+
 /*
  * cpu_v7_switch_mm(pgd_phys, tsk)
  *
@@ -47,10 +55,11 @@
  */
 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
+	ldr	r2, [r2, #MM_CONTEXT_ID]	@ get mm->context.id
+	and	r2, r2, #0xff
+	mov	r2, r2, lsl #(48 - 32)		@ ASID
+	orr	rpgdh, rpgdh, r2		@ 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] 29+ messages in thread

* [PATCH v3 RESEND 11/17] ARM: LPAE: use 64-bit accessors for TTBR registers
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (9 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 10/17] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 12/17] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
                   ` (5 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 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..2d270b8 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)				\
+			: : );					\
+		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 4e07eec..f03437e 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] 29+ messages in thread

* [PATCH v3 RESEND 12/17] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (10 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 11/17] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 13/17] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
                   ` (4 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 f3e8f88..19221c2 100644
--- a/arch/arm/include/asm/memory.h
+++ b/arch/arm/include/asm/memory.h
@@ -315,6 +315,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] 29+ messages in thread

* [PATCH v3 RESEND 13/17] ARM: LPAE: factor out T1SZ and TTBR1 computations
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (11 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 12/17] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 14/17] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
                   ` (3 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 c4f4251..5d93f00 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -128,18 +128,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] 29+ messages in thread

* [PATCH v3 RESEND 14/17] ARM: LPAE: accomodate >32-bit addresses for page table base
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (12 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 13/17] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 15/17] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
                   ` (2 subsequent siblings)
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 19221c2..8255b8f 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 5d93f00..e920763 100644
--- a/arch/arm/mm/proc-v7-3level.S
+++ b/arch/arm/mm/proc-v7-3level.S
@@ -111,6 +111,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
@@ -130,8 +131,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] 29+ messages in thread

* [PATCH v3 RESEND 15/17] ARM: mm: use physical addresses in highmem sanity checks
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (13 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 14/17] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 16/17] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 17/17] ARM: mm: clean up membank size limit checks Cyril Chemparathy
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 8db7c74..fcdc185 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 - 1) >= vmalloc_min ||
-		    __va(bank->start + bank->size - 1) <= __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] 29+ messages in thread

* [PATCH v3 RESEND 16/17] ARM: mm: cleanup checks for membank overlap with vmalloc area
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (14 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 15/17] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  2012-09-21 15:56 ` [PATCH v3 RESEND 17/17] ARM: mm: clean up membank size limit checks Cyril Chemparathy
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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>
Acked-by: Nicolas Pitre <nico@linaro.org>
---
 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 fcdc185..e631f73 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] 29+ messages in thread

* [PATCH v3 RESEND 17/17] ARM: mm: clean up membank size limit checks
  2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
                   ` (15 preceding siblings ...)
  2012-09-21 15:56 ` [PATCH v3 RESEND 16/17] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
@ 2012-09-21 15:56 ` Cyril Chemparathy
  16 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-21 15:56 UTC (permalink / raw)
  To: linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely, Cyril Chemparathy

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 e631f73..794457a 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] 29+ messages in thread

* Re: [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
@ 2012-09-22 15:10   ` Nicolas Pitre
  2012-09-22 21:41     ` Cyril Chemparathy
  2012-09-24 12:06   ` Dave Martin
  1 sibling, 1 reply; 29+ messages in thread
From: Nicolas Pitre @ 2012-09-22 15:10 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux, linux-arm-kernel, linux-kernel, arnd, catalin.marinas,
	davidb, frank.rowand, hsweeten, linus.walleij, marc.zyngier,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On Fri, 21 Sep 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>

There is another problem with this.

[...]
> diff --git a/arch/arm/include/asm/runtime-patch.h b/arch/arm/include/asm/runtime-patch.h
> new file mode 100644
> index 0000000..366444d
> --- /dev/null
> +++ b/arch/arm/include/asm/runtime-patch.h
> @@ -0,0 +1,208 @@
> +/*
> + * 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];
> +};

This causes the following compilation error:

  CC      sound/core/pcm.o
In file included from sound/core/pcm.c:293:0:
include/linux/soundcard.h:223:8: error: redefinition of 'struct patch_info'
arch/arm/include/asm/runtime-patch.h:28:8: note: originally defined here
make[2]: *** [sound/core/pcm.o] Error 1

The problem is that asm/runtime-patch.h gets included by asm/memory.h 
and asm/memory.h is included by almost the entire kernel. Something like 
"struct patch_info" is a bit too generic a name to be exported to the 
world as the likelihood of a name collision with some private definition 
in a driver or the like is rather high.  

In that context it might be worth moving everything that is not required 
for the patch stub definitions out of asm/runtime-patch.h.  For example, 
the definition of struct patch_info, struct patch_info_imm8, 
patch_next() and patch_data() could be moved to runtime-patch.c directly 
instead.  And then patch_stub() should be renamed to 
runtime_patch_stub(), early_patch_stub() to early_runtime_patch_stub(), 
patch_imm8() to runtime_patch_imm8(), etc.  Even the __IMM8 symbol name 
is rather weak for kernel wide scope.


Nicolas

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

* Re: [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-09-21 15:56 ` [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
@ 2012-09-22 15:24   ` Nicolas Pitre
  2012-09-24 16:31   ` Dave Martin
  1 sibling, 0 replies; 29+ messages in thread
From: Nicolas Pitre @ 2012-09-22 15:24 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux, linux-arm-kernel, linux-kernel, arnd, catalin.marinas,
	davidb, frank.rowand, hsweeten, linus.walleij, marc.zyngier,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On Fri, 21 Sep 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>

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


> ---
>  arch/arm/include/asm/memory.h |   38 ++++++++++++++++++++++++++++++++++++--
>  arch/arm/kernel/head.S        |    4 ++++
>  arch/arm/kernel/setup.c       |    2 +-
>  3 files changed, 41 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index 88ca206..f3e8f88 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -154,13 +154,47 @@
>  #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;
> +	phys_addr_t t;
> +
> +#ifndef CONFIG_ARM_LPAE
>  	early_patch_imm8("add", t, x, __pv_offset, 0);
> +#else
> +	unsigned long __tmp;
> +
> +#ifndef __ARMEB__
> +#define PV_PHYS_HIGH	"(__pv_phys_offset + 4)"
> +#else
> +#define PV_PHYS_HIGH	"__pv_phys_offset"
> +#endif
> +
> +	early_patch_stub(
> +	/* type */		PATCH_IMM8,
> +	/* code */
> +		"ldr		%[tmp], =__pv_offset\n"
> +		"ldr		%[tmp], [%[tmp]]\n"
> +		"add		%Q[to], %[from], %[tmp]\n"
> +		"ldr		%[tmp], =" PV_PHYS_HIGH "\n"
> +		"ldr		%[tmp], [%[tmp]]\n"
> +		"mov		%R[to], %[tmp]\n",
> +	/* pad */		4,
> +	/* patch_data */
> +		".long		__pv_offset\n"
> +		"add		%Q[to], %[from], %[imm]\n"
> +		".long	"	PV_PHYS_HIGH "\n"
> +		"mov		%R[to], %[imm]\n",
> +	/* operands */
> +		: [to]	 "=r"	(t),
> +		  [tmp]	 "=&r"	(__tmp)
> +		: [from] "r"	(x),
> +		  [imm]	 "I"	(__IMM8),
> +			 "i"	(&__pv_offset),
> +			 "i"	(&__pv_phys_offset));
> +#endif
>  	return t;
>  }
>  
> 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	[flat|nested] 29+ messages in thread

* Re: [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-22 15:10   ` Nicolas Pitre
@ 2012-09-22 21:41     ` Cyril Chemparathy
  0 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-22 21:41 UTC (permalink / raw)
  To: Nicolas Pitre
  Cc: linux, linux-arm-kernel, linux-kernel, arnd, catalin.marinas,
	davidb, frank.rowand, hsweeten, linus.walleij, marc.zyngier,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On 09/22/12 11:10, Nicolas Pitre wrote:
> On Fri, 21 Sep 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>
>
> There is another problem with this.
>
> [...]
>> diff --git a/arch/arm/include/asm/runtime-patch.h b/arch/arm/include/asm/runtime-patch.h
>> new file mode 100644
>> index 0000000..366444d
>> --- /dev/null
>> +++ b/arch/arm/include/asm/runtime-patch.h
>> @@ -0,0 +1,208 @@
>> +/*
>> + * 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];
>> +};
>
> This causes the following compilation error:
>
>    CC      sound/core/pcm.o
> In file included from sound/core/pcm.c:293:0:
> include/linux/soundcard.h:223:8: error: redefinition of 'struct patch_info'
> arch/arm/include/asm/runtime-patch.h:28:8: note: originally defined here
> make[2]: *** [sound/core/pcm.o] Error 1
>
> The problem is that asm/runtime-patch.h gets included by asm/memory.h
> and asm/memory.h is included by almost the entire kernel. Something like
> "struct patch_info" is a bit too generic a name to be exported to the
> world as the likelihood of a name collision with some private definition
> in a driver or the like is rather high.
>
> In that context it might be worth moving everything that is not required
> for the patch stub definitions out of asm/runtime-patch.h.  For example,
> the definition of struct patch_info, struct patch_info_imm8,
> patch_next() and patch_data() could be moved to runtime-patch.c directly
> instead.  And then patch_stub() should be renamed to
> runtime_patch_stub(), early_patch_stub() to early_runtime_patch_stub(),
> patch_imm8() to runtime_patch_imm8(), etc.  Even the __IMM8 symbol name
> is rather weak for kernel wide scope.
>

Thanks for trying this out.  I'll take this up in the next rev.

-- Cyril.

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

* Re: [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
  2012-09-22 15:10   ` Nicolas Pitre
@ 2012-09-24 12:06   ` Dave Martin
  2012-09-24 14:49     ` Cyril Chemparathy
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Martin @ 2012-09-24 12:06 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux, catalin.marinas, linus.walleij, will.deacon, grant.likely,
	paul.gortmaker, vincent.guittot, nico, davidb, plagnioj, arnd,
	marc.zyngier, rob.herring, vitalya, tglx, linux-arm-kernel,
	rmallon, frank.rowand, sjg, sboyd, linux-kernel, rabin, hsweeten,
	tj

On Fri, Sep 21, 2012 at 11:55:59AM -0400, 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.

There are currently a few different patching mechanisms in the kernel, and
it would be good if we could collect more of them under some common
framework.

For example, it might be possible to do the SMP-on-UP fixups using the same
framework you propose.  Best not to attempt that yet, though.


Overall, this looks well thought out and useful, though it looks like it
has a few issues that need attention.

Comments below.

Cheers
---Dave

> 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.

You might find that the "n" constraint works.  The explanation in the
GCC docs is pretty incomprehensible, but at least it exists.

__stringify hacks are not uncommon anyway though, so it's not a problem
either way.

> 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 |  208 ++++++++++++++++++++++++++++++++++
>  arch/arm/kernel/Makefile             |    1 +
>  arch/arm/kernel/module.c             |    9 +-
>  arch/arm/kernel/runtime-patch.c      |  193 +++++++++++++++++++++++++++++++
>  arch/arm/kernel/setup.c              |    3 +
>  arch/arm/kernel/vmlinux.lds.S        |   10 ++
>  8 files changed, 433 insertions(+), 1 deletion(-)
>  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 2f88d8d..98a3a1a 100644
> --- a/arch/arm/Kconfig
> +++ b/arch/arm/Kconfig
> @@ -60,6 +60,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..366444d
> --- /dev/null
> +++ b/arch/arm/include/asm/runtime-patch.h
> @@ -0,0 +1,208 @@
> +/*
> + * 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_IMM8		0x0001
> +struct patch_info_imm8 {
> +	u32		*imm;
> +	u32		 insn;
> +};
> +
> +#define patch_next(p)	((void *)(p) + sizeof(*(p)) + (p)->data_size)
> +#define patch_data(p)	((void *)&(p)->data[0])
> +
> +#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, pad, patch_data, ...)		\
> +	__asm__("@ patch stub\n"					\
> +		"1:\n"							\
> +		"	b	6f\n"					\
> +		"	.fill	" __stringify(pad) ", 1, 0\n"		\

What is the pad argument for?  It never seems to be set to anything other
than 0 in your series.

The compiler uses a pretty dumb heuristic to guess the size of asms:
4 * (number of ; or \n in the string)

Directives that the compiler can't predict the size of are not safe if
they output into any segment that the compiler uses.  .fill/.skip are
obvious candidates, but macro expansions, .rept, .irp etc. can cause
these problems too.

For example:

	void g(int);
	void f(void)
	{
		g(0xd00dfeed);
		asm(".skip 0x1000");
	}

If you try building this with gcc -marm -Os for example:

/tmp/ccXYm1uP.s: Assembler messages:
/tmp/ccXYm1uP.s:21: Error: bad immediate value for offset (4100)

...because the assembler assumes that it can dump a literal at the end
of the function and reference it from the g() callsite.


It may be that you have some intended future use for pad (such as
pasting one instruction sequence in place of another possibly
differently-sized sequence at fixup time), in which case this might
require a bit more thought.

> +		"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"					\
> +		"	.pushsection .runtime.patch.code, \"ax\"\n"	\

I have a vague feeling that this should have .text in the name somewhere,
since it is code that gets executed in place.

> +		"6:\n"							\
> +		code							\
> +		"	b 2b\n"						\

.ltorg

(See [1] below.)

> +		"	.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

If I've understood correctly, then this description is a bit misleading.
sym is not an absolute operand, but rather *(sym + ofs) is a
variable containing the fixup operand.

> + *		  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, _ofs)			\

Why are the _sym and _ofs parameters separate?  Nothing in your series
seems to requre _sym to be a symbol or _ofs to be a number; and nothing
passes _ofs != 0, but anyway I don't see why the caller can't add those
two values together in the macro argument.

> +	patch_stub(							\
> +		/* type */						\
> +			PATCH_IMM8,					\
> +		/* code */						\
> +			_insn "	%[to], %[from], %[imm]\n",		\
> +		/* patch_data */					\
> +			".long " __stringify(_sym + _ofs) "\n"		\

If _sym or _ofs is a complex expression, the + may mis-bind.  If the
_ofs parameter is needed at all, it would probably be a good idea to
have parentheses around _sym and _ofs.

> +			_insn "	%[to], %[from], %[imm]\n",		\
> +		/* operands */						\
> +			: [to]	 "=r" (_to)				\
> +			: [from] "r"  (_from),				\
> +			  [imm]	 "I"  (__IMM8),				\
> +				 "i"  (&(_sym))				\
> +			: "cc")
> +
> +/*
> + * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
> + */
> +#define patch_imm8_mov(_insn, _to, _sym, _ofs)				\
> +	patch_stub(							\
> +		/* type */						\
> +			PATCH_IMM8,					\
> +		/* code */						\
> +			_insn "	%[to], %[imm]\n",			\
> +		/* patch_data */					\
> +			".long " __stringify(_sym + _ofs) "\n"		\
> +			_insn "	%[to], %[imm]\n",			\
> +		/* operands */						\
> +			: [to]	"=r" (_to)				\
> +			: [imm]	"I"  (__IMM8),				\
> +				"i"  (&(_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, _ofs)			\
> +do {									\
> +	unsigned long __tmp;						\
> +	early_patch_stub(						\
> +		/* type */						\
> +			PATCH_IMM8,					\
> +		/* code */						\
> +			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\

This would not be OK if assembled into the .text section, for the reasons
described above.  (The compiler doesn't know about the extra data word
injected by the ldr= pseudo-instruction.)

early_patch_stub puts <code> into a custom section, so that's OK.

However, there's still nothing to ensure that the literal word is in
range of the load.  That can be fixed with an .ltorg to dump out the
literal(s) right after the branch following <code> in early_patch_stub.

> +			"ldr	%[tmp], [%[tmp]]\n"			\
> +			_insn "	%[to], %[from], %[tmp]\n",		\
> +		/* pad */						\
> +			0,						\
> +		/* patch_data */					\
> +			".long " __stringify(_sym + _ofs) "\n"		\
> +			_insn "	%[to], %[from], %[imm]\n",		\
> +		/* operands */						\
> +			: [to]	 "=r"  (_to),				\
> +			  [tmp]	 "=&r" (__tmp)				\
> +			: [from] "r"   (_from),				\
> +			  [imm]	 "I"   (__IMM8),			\
> +				 "i"   (&(_sym))			\
> +			: "cc");					\

Should we have "cc" here?

Since this macro is only used with a single instruction _insn, there
would be no way to make use of a condition set by that instruction.

Therefore, flag-setting instructions don't really make any sense here,
and "cc" could be removed.

If so, it could make sense for the apply_patch_imm8() implementation
to check for and reject flag-setting encodings.

> +} while (0)
> +
> +#define early_patch_imm8_mov(_insn, _to, _sym, _ofs)			\
> +do {									\
> +	unsigned long __tmp;						\
> +	early_patch_stub(						\
> +		/* type */						\
> +			PATCH_IMM8					\
> +		/* code */						\
> +			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\
> +			"ldr	%[tmp], [%[tmp]]\n"			\
> +			_insn "	%[to], %[tmp]\n",			\
> +		/* pad */						\
> +			0,						\
> +		/* patch_data */					\
> +			".long " __stringify(_sym + _ofs) "\n"		\
> +			_insn " %[to], %[imm]\n",			\
> +		/* operands */						\
> +			: [to]	"=r"  (_to),				\
> +			  [tmp]	"=&r" (__tmp)				\
> +			: [imm]	"I"   (__IMM8),				\
> +				"i"   (&(_sym))				\
> +			: "cc");					\
> +} while (0)
> +
> +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..0b16b94 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 patch.o
>  
>  extra-y := $(head-y) vmlinux.lds
> diff --git a/arch/arm/kernel/module.c b/arch/arm/kernel/module.c
> index 1e9be5d..10a2922 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
>  /*
> @@ -276,7 +277,7 @@ int module_finalize(const Elf32_Ehdr *hdr, const Elf_Shdr *sechdrs,
>  	const char *secstrs = (void *)hdr + sechdrs[hdr->e_shstrndx].sh_offset;
>  	const Elf_Shdr *sechdrs_end = sechdrs + hdr->e_shnum;
>  	struct mod_unwind_map maps[ARM_SEC_MAX];
> -	int i;
> +	int i, err;
>  
>  	memset(maps, 0, sizeof(maps));
>  
> @@ -321,6 +322,12 @@ 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) {
> +		err = runtime_patch((void *)s->sh_addr, s->sh_size);
> +		if (err)
> +			return err;
> +	}
>  	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..28a6367
> --- /dev/null
> +++ b/arch/arm/kernel/runtime-patch.c
> @@ -0,0 +1,193 @@
> +/*
> + * 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>
> +
> +#include "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);
> +}

This function appears unused.

Do we actually do the cache flushing anywhere?

> +
> +#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;

You need to convert this back to memory order.  If fixups might be
applied while the MMU is off, misaligned 32-bit accesses will fail.
It's better to store the two halfwords separately:

	__opcode_to_mem_thumb16(__opcode_thumb32_first(foo))
	__opcode_to_mem_thumb16(__opcode_thumb32_second(foo))

If the MMU is on, you can use __opcode_to_mem_thumb32(foo) and do
a possibly misaligned store, though.

This may be a good idea even if the MMU is on, because fixup is a
once-only process and we don't expect a meaningful performance
impact from that, especially when caching is enabled.  But splitting
the access may also make it easier to reuse the framework in
situations where the cache and MMU are off.

Because of all this, I suggest you don't repeatedly modify *ninsn.
Preparing the value and then writing it (or each half) once is probably
cleaner.

> +
> +	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;

You need __opcode_to_mem_arm() to convert this back to memory order.

> +
> +	return 0;
> +}
> +
> +#endif	/* CONFIG_THUMB2_KERNEL */
> +
> +static int apply_patch_imm8(const struct patch_info *p)
> +{
> +	u32 *insn_ptr = p->insn, ninsn;
> +	int count = p->insn_size / sizeof(u32);
> +	const struct patch_info_imm8 *info;
> +	int err;
> +
> +
> +	if (count <= 0 || p->data_size != count * sizeof(*info)) {
> +		pr_err("patch: bad patch, insn size %d, data size %d\n",
> +		       p->insn_size, p->data_size);
> +		return -EINVAL;
> +	}
> +
> +	for (info = patch_data(p); count; count--, info++, insn_ptr++) {
> +		err = do_patch_imm8(info->insn, *info->imm, &ninsn);
> +		if (err)
> +			return err;
> +		__patch_text(insn_ptr, ninsn);
> +	}
> +
> +
> +	return 0;
> +}
> +
> +int runtime_patch(const void *table, unsigned size)

Minor nits: the type-unsafety could be dealt with outside this function;
table could be struct patch_info const *.

Also, why do we not just pass end to this function instead of subtracting
the table base and then adding it back again?

> +{
> +	const struct patch_info *p = table, *end = (table + size);
> +
> +	for (p = table; p < end; p = patch_next(p)) {
> +		int err = -EINVAL;
> +
> +		if (p->type == PATCH_IMM8)
> +			err = apply_patch_imm8(p);
> +		if (err)
> +			return err;
> +	}
> +	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
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

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

* Re: [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size
  2012-09-21 15:56 ` [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
@ 2012-09-24 13:38   ` Russell King - ARM Linux
  2012-09-24 14:00     ` Cyril Chemparathy
  0 siblings, 1 reply; 29+ messages in thread
From: Russell King - ARM Linux @ 2012-09-24 13:38 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On Fri, Sep 21, 2012 at 11:56:07AM -0400, 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.

The description needs updating.  You're no longer using phys_addr_t for the
initrd size.

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

* Re: [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions
  2012-09-21 15:56 ` [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
@ 2012-09-24 13:54   ` Russell King - ARM Linux
  0 siblings, 0 replies; 29+ messages in thread
From: Russell King - ARM Linux @ 2012-09-24 13:54 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On Fri, Sep 21, 2012 at 11:56:04AM -0400, 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))

It's strange.  Every other platform in the kernel, including those with
PAE, manage to get away with defining PAGE_MASK as the original above
(see asm-generic/pgtable.h)  Why is ARM any different?

Note that PAGE_MASK gets used at the moment on ARM for both virtual and
physical addresses.  x86 has PHYSICAL_PAGE_MASK for masking physical
addresses.  Maybe we should adopt the same approach?

Whatever, I feel that we should not deviate from the established
definitions across every other architecture.

>  
>  #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))

These masks are applied to a _virtual_ kernel address, not the physical
addresses,  Even with LPAE, the virtual address space is still 32-bit.

So this is definitely wrong.

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

* Re: [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size
  2012-09-24 13:38   ` Russell King - ARM Linux
@ 2012-09-24 14:00     ` Cyril Chemparathy
  0 siblings, 0 replies; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-24 14:00 UTC (permalink / raw)
  To: Russell King - ARM Linux
  Cc: linux-arm-kernel, linux-kernel, arnd, catalin.marinas, davidb,
	frank.rowand, hsweeten, linus.walleij, marc.zyngier, nico,
	paul.gortmaker, plagnioj, rabin, rmallon, rob.herring, sboyd,
	sjg, tglx, tj, vincent.guittot, vitalya, will.deacon,
	grant.likely

On 09/24/12 09:38, Russell King - ARM Linux wrote:
> On Fri, Sep 21, 2012 at 11:56:07AM -0400, 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.
>
> The description needs updating.  You're no longer using phys_addr_t for the
> initrd size.
>

Thanks.  Nico had pointed this out earlier.  I've fixed for v4.

Thanks
-- Cyril.

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

* Re: [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-24 12:06   ` Dave Martin
@ 2012-09-24 14:49     ` Cyril Chemparathy
  2012-09-24 15:54       ` Dave Martin
  0 siblings, 1 reply; 29+ messages in thread
From: Cyril Chemparathy @ 2012-09-24 14:49 UTC (permalink / raw)
  To: Dave Martin
  Cc: linux, catalin.marinas, linus.walleij, will.deacon, grant.likely,
	paul.gortmaker, vincent.guittot, nico, davidb, plagnioj, arnd,
	marc.zyngier, rob.herring, vitalya, tglx, linux-arm-kernel,
	rmallon, frank.rowand, sjg, sboyd, linux-kernel, rabin, hsweeten,
	tj

Hi Dave,

Thanks for the detailed review...

On 9/24/2012 8:06 AM, Dave Martin wrote:
> On Fri, Sep 21, 2012 at 11:55:59AM -0400, 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.
>
> There are currently a few different patching mechanisms in the kernel, and
> it would be good if we could collect more of them under some common
> framework.
>

That would be great!  I could use some pointers here.  I've looked at 
the kprobes code, and there doesn't appear to be much of an intersection 
there...

> For example, it might be possible to do the SMP-on-UP fixups using the same
> framework you propose.  Best not to attempt that yet, though.
>

... and I've looked at the ALT_SMP/ALT_UP stuff as well.  The problem 
here appears to be that ALT_SMP is needed way early in boot - up in 
head.S assembly-land.

The third place is probably the jump label mechanism.  That may be a fit 
with some work, but I'm not sure yet.

> Overall, this looks well thought out and useful, though it looks like it
> has a few issues that need attention.
>
> Comments below.
>
> Cheers
> ---Dave
>
[...]
>> 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.
>
> You might find that the "n" constraint works.  The explanation in the
> GCC docs is pretty incomprehensible, but at least it exists.
>
> __stringify hacks are not uncommon anyway though, so it's not a problem
> either way.
>

The stringify hack is nasty, and I'd like to get rid of it if I could...

I looked up constraints.md, and couldn't find "n" defined as a 
constraint.  For that matter, I couldn't find "n" being handled as a 
modifier in arm_print_operand() either.  BTW, I'm looking at GCC 4.6 for 
these.

Could you please point me to the doc in question that lists this 
constraint/modifier?  Is this specific to newer (or older) versions of GCC.

[...]
>> +#define early_patch_stub(type, code, pad, patch_data, ...)		\
>> +	__asm__("@ patch stub\n"					\
>> +		"1:\n"							\
>> +		"	b	6f\n"					\
>> +		"	.fill	" __stringify(pad) ", 1, 0\n"		\
>
> What is the pad argument for?  It never seems to be set to anything other
> than 0 in your series.
>

The pad argument is used when we need more than one 32-bit instruction 
slot in the straight line (post patch) code path.  Please look at patch 
05/17 of the series (ARM: LPAE: support 64-bit virt_to_phys patching). 
When we patch 64-bit virt_to_phys(), we need that extra slot to fill up 
the upper 32-bits of the result.

> The compiler uses a pretty dumb heuristic to guess the size of asms:
> 4 * (number of ; or \n in the string)
>
> Directives that the compiler can't predict the size of are not safe if
> they output into any segment that the compiler uses.  .fill/.skip are
> obvious candidates, but macro expansions, .rept, .irp etc. can cause
> these problems too.
>
> For example:
>
> 	void g(int);
> 	void f(void)
> 	{
> 		g(0xd00dfeed);
> 		asm(".skip 0x1000");
> 	}
>
> If you try building this with gcc -marm -Os for example:
>
> /tmp/ccXYm1uP.s: Assembler messages:
> /tmp/ccXYm1uP.s:21: Error: bad immediate value for offset (4100)
>
> ...because the assembler assumes that it can dump a literal at the end
> of the function and reference it from the g() callsite.
>
>
> It may be that you have some intended future use for pad (such as
> pasting one instruction sequence in place of another possibly
> differently-sized sequence at fixup time), in which case this might
> require a bit more thought.
>

Good point.  Thanks.

I'm not sure if this helps, but I don't think pad should be used to 
insert more than a couple of instruction words into the 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"					\
>> +		"	.pushsection .runtime.patch.code, \"ax\"\n"	\
>
> I have a vague feeling that this should have .text in the name somewhere,
> since it is code that gets executed in place.
>

Fair enough.  Will change to .runtime.patch.text instead.

>> +		"6:\n"							\
>> +		code							\
>> +		"	b 2b\n"						\
>
> .ltorg
>
> (See [1] below.)
>
>> +		"	.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
>
> If I've understood correctly, then this description is a bit misleading.
> sym is not an absolute operand, but rather *(sym + ofs) is a
> variable containing the fixup operand.
>

Correct.  I'll clarify in the text.

>> + *		  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, _ofs)			\
>
> Why are the _sym and _ofs parameters separate?  Nothing in your series
> seems to requre _sym to be a symbol or _ofs to be a number; and nothing
> passes _ofs != 0, but anyway I don't see why the caller can't add those
> two values together in the macro argument.
>

I could (should) really get rid of ofs.  This is a hold over from 
earlier versions of the patch, where we were using the ofs to point to 
the upper 32-bits of the phys_offset ( = 4 for LE, 0 for BE).

I will clean this up in the next rev.  Thanks.

>> +	patch_stub(							\
>> +		/* type */						\
>> +			PATCH_IMM8,					\
>> +		/* code */						\
>> +			_insn "	%[to], %[from], %[imm]\n",		\
>> +		/* patch_data */					\
>> +			".long " __stringify(_sym + _ofs) "\n"		\
>
> If _sym or _ofs is a complex expression, the + may mis-bind.  If the
> _ofs parameter is needed at all, it would probably be a good idea to
> have parentheses around _sym and _ofs.
>

I'm guessing this doesn't apply once we get rid of ofs?

>> +			_insn "	%[to], %[from], %[imm]\n",		\
>> +		/* operands */						\
>> +			: [to]	 "=r" (_to)				\
>> +			: [from] "r"  (_from),				\
>> +			  [imm]	 "I"  (__IMM8),				\
>> +				 "i"  (&(_sym))				\
>> +			: "cc")
>> +
>> +/*
>> + * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
>> + */
>> +#define patch_imm8_mov(_insn, _to, _sym, _ofs)				\
>> +	patch_stub(							\
>> +		/* type */						\
>> +			PATCH_IMM8,					\
>> +		/* code */						\
>> +			_insn "	%[to], %[imm]\n",			\
>> +		/* patch_data */					\
>> +			".long " __stringify(_sym + _ofs) "\n"		\
>> +			_insn "	%[to], %[imm]\n",			\
>> +		/* operands */						\
>> +			: [to]	"=r" (_to)				\
>> +			: [imm]	"I"  (__IMM8),				\
>> +				"i"  (&(_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, _ofs)			\
>> +do {									\
>> +	unsigned long __tmp;						\
>> +	early_patch_stub(						\
>> +		/* type */						\
>> +			PATCH_IMM8,					\
>> +		/* code */						\
>> +			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\
>
> This would not be OK if assembled into the .text section, for the reasons
> described above.  (The compiler doesn't know about the extra data word
> injected by the ldr= pseudo-instruction.)
>
> early_patch_stub puts <code> into a custom section, so that's OK.
>
> However, there's still nothing to ensure that the literal word is in
> range of the load.  That can be fixed with an .ltorg to dump out the
> literal(s) right after the branch following <code> in early_patch_stub.
>
>> +			"ldr	%[tmp], [%[tmp]]\n"			\
>> +			_insn "	%[to], %[from], %[tmp]\n",		\
>> +		/* pad */						\
>> +			0,						\
>> +		/* patch_data */					\
>> +			".long " __stringify(_sym + _ofs) "\n"		\
>> +			_insn "	%[to], %[from], %[imm]\n",		\
>> +		/* operands */						\
>> +			: [to]	 "=r"  (_to),				\
>> +			  [tmp]	 "=&r" (__tmp)				\
>> +			: [from] "r"   (_from),				\
>> +			  [imm]	 "I"   (__IMM8),			\
>> +				 "i"   (&(_sym))			\
>> +			: "cc");					\
>
> Should we have "cc" here?
>
> Since this macro is only used with a single instruction _insn, there
> would be no way to make use of a condition set by that instruction.
>
> Therefore, flag-setting instructions don't really make any sense here,
> and "cc" could be removed.
>
> If so, it could make sense for the apply_patch_imm8() implementation
> to check for and reject flag-setting encodings.
>

That makes sense.  I've modified the do_patch_imm8() functions to 
explicitly check for attempts to set condition codes, and removed the "cc".

[...]
>> diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
>> new file mode 100644
>> index 0000000..28a6367
>> --- /dev/null
>> +++ b/arch/arm/kernel/runtime-patch.c
[...]
>> +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);
>> +}
>
> This function appears unused.
>

Indeed.  This function should have been removed.  Thanks.

> Do we actually do the cache flushing anywhere?
>

Yes, in __patch_text().

[...]
>> +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
>> +{
[...]
>> +	*ninsn  = insn & ~(BIT(26) | 0x7 << 12 | 0xff);
>> +	*ninsn |= (rot >> 3) << 26;	/* field "i" */
>> +	*ninsn |= (rot & 0x7) << 12;	/* field "imm3" */
>> +	*ninsn |= val;
>
> You need to convert this back to memory order.  If fixups might be
> applied while the MMU is off, misaligned 32-bit accesses will fail.
> It's better to store the two halfwords separately:
>
> 	__opcode_to_mem_thumb16(__opcode_thumb32_first(foo))
> 	__opcode_to_mem_thumb16(__opcode_thumb32_second(foo))
>
> If the MMU is on, you can use __opcode_to_mem_thumb32(foo) and do
> a possibly misaligned store, though.
>
> This may be a good idea even if the MMU is on, because fixup is a
> once-only process and we don't expect a meaningful performance
> impact from that, especially when caching is enabled.  But splitting
> the access may also make it easier to reuse the framework in
> situations where the cache and MMU are off.
>
> Because of all this, I suggest you don't repeatedly modify *ninsn.
> Preparing the value and then writing it (or each half) once is probably
> cleaner.
>
[...]
>> +static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
[...]
>> +	/* patch in new immediate and rotation */
>> +	*ninsn = (insn & ~0xfff) | (rot << 8) | val;
>
> You need __opcode_to_mem_arm() to convert this back to memory order.
>

The do_patch_imm8() functions do not write to the instruction.  The 
ninsn pointer here is not a pointer to the instruction that is being 
patched, it is simply a pointer used to return a value to the caller 
(apply_patch_imm8()).

The instruction is written in apply_patch_imm8():

	u32 ninsn;
	...
	err = do_patch_imm8(info->insn, *info->imm, &ninsn);
	if (err)
		return err;
	__patch_text(insn_ptr, ninsn);

Here the __patch_text() call converts the instruction and performs the 
actual write.  If I read this correctly, the __patch_text() code takes 
care of the splitting up thumb2 instructions as you've indicated.

[...]
>> +int runtime_patch(const void *table, unsigned size)
>
> Minor nits: the type-unsafety could be dealt with outside this function;
> table could be struct patch_info const *.
>
> Also, why do we not just pass end to this function instead of subtracting
> the table base and then adding it back again?
>

In addition to the internal usage within runtime-patch.c, this function 
is called from module.c.  In the module load case, the base + size form 
is more convenient.

Second, based on Nico's comments about keeping the namespace clean, I've 
now moved the structure definitions to runtime-patch.c.  These types are 
no longer exposed, and so we have to keep them opaque in this interface.

[...]

-- 
Thanks
- Cyril

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

* Re: [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching
  2012-09-24 14:49     ` Cyril Chemparathy
@ 2012-09-24 15:54       ` Dave Martin
  0 siblings, 0 replies; 29+ messages in thread
From: Dave Martin @ 2012-09-24 15:54 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux, catalin.marinas, linus.walleij, will.deacon, grant.likely,
	paul.gortmaker, vincent.guittot, nico, davidb, plagnioj, arnd,
	marc.zyngier, rob.herring, vitalya, tglx, linux-arm-kernel,
	rmallon, frank.rowand, sjg, sboyd, linux-kernel, rabin, hsweeten,
	tj

On Mon, Sep 24, 2012 at 10:49:34AM -0400, Cyril Chemparathy wrote:
> Hi Dave,
> 
> Thanks for the detailed review...
> 
> On 9/24/2012 8:06 AM, Dave Martin wrote:
> >On Fri, Sep 21, 2012 at 11:55:59AM -0400, 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.
> >
> >There are currently a few different patching mechanisms in the kernel, and
> >it would be good if we could collect more of them under some common
> >framework.
> >
> 
> That would be great!  I could use some pointers here.  I've looked
> at the kprobes code, and there doesn't appear to be much of an
> intersection there...

Well, I think we shouldn't try it for now.  I think kprobes is
doing something different enough that it doesn't necessarily make
sense to unify that.

If your patches are useful as-is, we shouldn't worry about adding
features until later.

> >For example, it might be possible to do the SMP-on-UP fixups using the same
> >framework you propose.  Best not to attempt that yet, though.
> >
> 
> ... and I've looked at the ALT_SMP/ALT_UP stuff as well.  The
> problem here appears to be that ALT_SMP is needed way early in boot
> - up in head.S assembly-land.

Indeed, this would need some thought.  Again, this is just a "maybe".
No need to try it right now.

> 
> The third place is probably the jump label mechanism.  That may be a
> fit with some work, but I'm not sure yet.
> 
> >Overall, this looks well thought out and useful, though it looks like it
> >has a few issues that need attention.
> >
> >Comments below.
> >
> >Cheers
> >---Dave
> >
> [...]
> >>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.
> >
> >You might find that the "n" constraint works.  The explanation in the
> >GCC docs is pretty incomprehensible, but at least it exists.
> >
> >__stringify hacks are not uncommon anyway though, so it's not a problem
> >either way.
> >
> 
> The stringify hack is nasty, and I'd like to get rid of it if I could...
> 
> I looked up constraints.md, and couldn't find "n" defined as a
> constraint.  For that matter, I couldn't find "n" being handled as a
> modifier in arm_print_operand() either.  BTW, I'm looking at GCC 4.6
> for these.
> 
> Could you please point me to the doc in question that lists this
> constraint/modifier?  Is this specific to newer (or older) versions
> of GCC.

See the "Simple Constraints" section in the GCC docs.

However, it looks like "n" only works for operands which really do
evaluate to constant integers.  It doesn't work for expressions based
on symbols:

	void g(int);
        asm(".long %0" :: "n" (g));

tst.c:6:2: warning: asm operand 0 probably doesn't match constraints
tst.c:6:2: error: impossible constraint in 'asm'


So scratch that suggestion...  the __stringify() method looks better.

> 
> [...]
> >>+#define early_patch_stub(type, code, pad, patch_data, ...)		\
> >>+	__asm__("@ patch stub\n"					\
> >>+		"1:\n"							\
> >>+		"	b	6f\n"					\
> >>+		"	.fill	" __stringify(pad) ", 1, 0\n"		\
> >
> >What is the pad argument for?  It never seems to be set to anything other
> >than 0 in your series.
> >
> 
> The pad argument is used when we need more than one 32-bit
> instruction slot in the straight line (post patch) code path.
> Please look at patch 05/17 of the series (ARM: LPAE: support 64-bit
> virt_to_phys patching). When we patch 64-bit virt_to_phys(), we need
> that extra slot to fill up the upper 32-bits of the result.

I see -- it looks like I missed that.

I guess this is probably OK, given that for every instruction-sized
bit of padding, there should be a corresponding patch data definition
in the same asm block which increases GCC's guess about the size of
the asm at least enough to avoid fixup problems.

Used like this, there should probably be no problem.

> >The compiler uses a pretty dumb heuristic to guess the size of asms:
> >4 * (number of ; or \n in the string)
> >
> >Directives that the compiler can't predict the size of are not safe if
> >they output into any segment that the compiler uses.  .fill/.skip are
> >obvious candidates, but macro expansions, .rept, .irp etc. can cause
> >these problems too.
> >
> >For example:
> >
> >	void g(int);
> >	void f(void)
> >	{
> >		g(0xd00dfeed);
> >		asm(".skip 0x1000");
> >	}
> >
> >If you try building this with gcc -marm -Os for example:
> >
> >/tmp/ccXYm1uP.s: Assembler messages:
> >/tmp/ccXYm1uP.s:21: Error: bad immediate value for offset (4100)
> >
> >...because the assembler assumes that it can dump a literal at the end
> >of the function and reference it from the g() callsite.
> >
> >
> >It may be that you have some intended future use for pad (such as
> >pasting one instruction sequence in place of another possibly
> >differently-sized sequence at fixup time), in which case this might
> >require a bit more thought.
> >
> 
> Good point.  Thanks.
> 
> I'm not sure if this helps, but I don't think pad should be used to
> insert more than a couple of instruction words into the code.

A directive which inserts <= 4 bytes is safe.  Anything else is not
safe (unless GCC overestimates the size of the asm for other reasons).

As I explain above, I now think we are actually OK in this case.

> >>+		"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"					\
> >>+		"	.pushsection .runtime.patch.code, \"ax\"\n"	\
> >
> >I have a vague feeling that this should have .text in the name somewhere,
> >since it is code that gets executed in place.
> >
> 
> Fair enough.  Will change to .runtime.patch.text instead.
> 
> >>+		"6:\n"							\
> >>+		code							\
> >>+		"	b 2b\n"						\
> >
> >.ltorg
> >
> >(See [1] below.)
> >
> >>+		"	.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
> >
> >If I've understood correctly, then this description is a bit misleading.
> >sym is not an absolute operand, but rather *(sym + ofs) is a
> >variable containing the fixup operand.
> >
> 
> Correct.  I'll clarify in the text.
> 
> >>+ *		  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, _ofs)			\
> >
> >Why are the _sym and _ofs parameters separate?  Nothing in your series
> >seems to requre _sym to be a symbol or _ofs to be a number; and nothing
> >passes _ofs != 0, but anyway I don't see why the caller can't add those
> >two values together in the macro argument.
> >
> 
> I could (should) really get rid of ofs.  This is a hold over from
> earlier versions of the patch, where we were using the ofs to point
> to the upper 32-bits of the phys_offset ( = 4 for LE, 0 for BE).
> 
> I will clean this up in the next rev.  Thanks.

Ah, OK.  Removing that extra argument should make things clearer.

> 
> >>+	patch_stub(							\
> >>+		/* type */						\
> >>+			PATCH_IMM8,					\
> >>+		/* code */						\
> >>+			_insn "	%[to], %[from], %[imm]\n",		\
> >>+		/* patch_data */					\
> >>+			".long " __stringify(_sym + _ofs) "\n"		\
> >
> >If _sym or _ofs is a complex expression, the + may mis-bind.  If the
> >_ofs parameter is needed at all, it would probably be a good idea to
> >have parentheses around _sym and _ofs.
> >
> 
> I'm guessing this doesn't apply once we get rid of ofs?

Sure, no problem.

> >>+			_insn "	%[to], %[from], %[imm]\n",		\
> >>+		/* operands */						\
> >>+			: [to]	 "=r" (_to)				\
> >>+			: [from] "r"  (_from),				\
> >>+			  [imm]	 "I"  (__IMM8),				\
> >>+				 "i"  (&(_sym))				\
> >>+			: "cc")
> >>+
> >>+/*
> >>+ * patch_imm8_mov() - same as patch_imm8(), but for mov/mvn instructions
> >>+ */
> >>+#define patch_imm8_mov(_insn, _to, _sym, _ofs)				\
> >>+	patch_stub(							\
> >>+		/* type */						\
> >>+			PATCH_IMM8,					\
> >>+		/* code */						\
> >>+			_insn "	%[to], %[imm]\n",			\
> >>+		/* patch_data */					\
> >>+			".long " __stringify(_sym + _ofs) "\n"		\
> >>+			_insn "	%[to], %[imm]\n",			\
> >>+		/* operands */						\
> >>+			: [to]	"=r" (_to)				\
> >>+			: [imm]	"I"  (__IMM8),				\
> >>+				"i"  (&(_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, _ofs)			\
> >>+do {									\
> >>+	unsigned long __tmp;						\
> >>+	early_patch_stub(						\
> >>+		/* type */						\
> >>+			PATCH_IMM8,					\
> >>+		/* code */						\
> >>+			"ldr	%[tmp], =" __stringify(_sym + _ofs) "\n"\
> >
> >This would not be OK if assembled into the .text section, for the reasons
> >described above.  (The compiler doesn't know about the extra data word
> >injected by the ldr= pseudo-instruction.)
> >
> >early_patch_stub puts <code> into a custom section, so that's OK.
> >
> >However, there's still nothing to ensure that the literal word is in
> >range of the load.  That can be fixed with an .ltorg to dump out the
> >literal(s) right after the branch following <code> in early_patch_stub.
> >
> >>+			"ldr	%[tmp], [%[tmp]]\n"			\
> >>+			_insn "	%[to], %[from], %[tmp]\n",		\
> >>+		/* pad */						\
> >>+			0,						\
> >>+		/* patch_data */					\
> >>+			".long " __stringify(_sym + _ofs) "\n"		\
> >>+			_insn "	%[to], %[from], %[imm]\n",		\
> >>+		/* operands */						\
> >>+			: [to]	 "=r"  (_to),				\
> >>+			  [tmp]	 "=&r" (__tmp)				\
> >>+			: [from] "r"   (_from),				\
> >>+			  [imm]	 "I"   (__IMM8),			\
> >>+				 "i"   (&(_sym))			\
> >>+			: "cc");					\
> >
> >Should we have "cc" here?
> >
> >Since this macro is only used with a single instruction _insn, there
> >would be no way to make use of a condition set by that instruction.
> >
> >Therefore, flag-setting instructions don't really make any sense here,
> >and "cc" could be removed.
> >
> >If so, it could make sense for the apply_patch_imm8() implementation
> >to check for and reject flag-setting encodings.
> >
> 
> That makes sense.  I've modified the do_patch_imm8() functions to
> explicitly check for attempts to set condition codes, and removed
> the "cc".

OK, cool.

> 
> [...]
> >>diff --git a/arch/arm/kernel/runtime-patch.c b/arch/arm/kernel/runtime-patch.c
> >>new file mode 100644
> >>index 0000000..28a6367
> >>--- /dev/null
> >>+++ b/arch/arm/kernel/runtime-patch.c
> [...]
> >>+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);
> >>+}
> >
> >This function appears unused.
> >
> 
> Indeed.  This function should have been removed.  Thanks.
> 
> >Do we actually do the cache flushing anywhere?
> >
> 
> Yes, in __patch_text().

OK, fine.

> 
> [...]
> >>+static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
> >>+{
> [...]
> >>+	*ninsn  = insn & ~(BIT(26) | 0x7 << 12 | 0xff);
> >>+	*ninsn |= (rot >> 3) << 26;	/* field "i" */
> >>+	*ninsn |= (rot & 0x7) << 12;	/* field "imm3" */
> >>+	*ninsn |= val;
> >
> >You need to convert this back to memory order.  If fixups might be
> >applied while the MMU is off, misaligned 32-bit accesses will fail.
> >It's better to store the two halfwords separately:
> >
> >	__opcode_to_mem_thumb16(__opcode_thumb32_first(foo))
> >	__opcode_to_mem_thumb16(__opcode_thumb32_second(foo))
> >
> >If the MMU is on, you can use __opcode_to_mem_thumb32(foo) and do
> >a possibly misaligned store, though.
> >
> >This may be a good idea even if the MMU is on, because fixup is a
> >once-only process and we don't expect a meaningful performance
> >impact from that, especially when caching is enabled.  But splitting
> >the access may also make it easier to reuse the framework in
> >situations where the cache and MMU are off.
> >
> >Because of all this, I suggest you don't repeatedly modify *ninsn.
> >Preparing the value and then writing it (or each half) once is probably
> >cleaner.
> >
> [...]
> >>+static int do_patch_imm8(u32 insn, u32 imm, u32 *ninsn)
> [...]
> >>+	/* patch in new immediate and rotation */
> >>+	*ninsn = (insn & ~0xfff) | (rot << 8) | val;
> >
> >You need __opcode_to_mem_arm() to convert this back to memory order.
> >
> 
> The do_patch_imm8() functions do not write to the instruction.  The
> ninsn pointer here is not a pointer to the instruction that is being
> patched, it is simply a pointer used to return a value to the caller
> (apply_patch_imm8()).
> 
> The instruction is written in apply_patch_imm8():
> 
> 	u32 ninsn;
> 	...
> 	err = do_patch_imm8(info->insn, *info->imm, &ninsn);
> 	if (err)
> 		return err;
> 	__patch_text(insn_ptr, ninsn);
> 
> Here the __patch_text() call converts the instruction and performs
> the actual write.  If I read this correctly, the __patch_text() code
> takes care of the splitting up thumb2 instructions as you've
> indicated.

OK, I think you're right.  I had vague memories about __patch_text(),
but I missed its use here (I was too busy searching for "flush"...)

This makes the do_patch_imm8() functions a bit weird though, because
they accept input in memory order but generate output in canonical
order.

That could be avoided by having an #ifdef in apply_patch_imm8() to
choose the correct conversion for the input, but that would be a bit
ugly.  Maybe just add a comment somewhere to clarify the different in
byte order, and the reason for it: this would make the code easier to
understand.

> 
> [...]
> >>+int runtime_patch(const void *table, unsigned size)
> >
> >Minor nits: the type-unsafety could be dealt with outside this function;
> >table could be struct patch_info const *.
> >
> >Also, why do we not just pass end to this function instead of subtracting
> >the table base and then adding it back again?
> >
> 
> In addition to the internal usage within runtime-patch.c, this
> function is called from module.c.  In the module load case, the base
> + size form is more convenient.
> 
> Second, based on Nico's comments about keeping the namespace clean,
> I've now moved the structure definitions to runtime-patch.c.  These
> types are no longer exposed, and so we have to keep them opaque in
> this interface.

OK, fair enough.  Those were very minor nits anyway.

[...]

Cheers
---Dave

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

* Re: [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-09-21 15:56 ` [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
  2012-09-22 15:24   ` Nicolas Pitre
@ 2012-09-24 16:31   ` Dave Martin
  2012-09-24 16:51     ` Nicolas Pitre
  1 sibling, 1 reply; 29+ messages in thread
From: Dave Martin @ 2012-09-24 16:31 UTC (permalink / raw)
  To: Cyril Chemparathy
  Cc: linux, catalin.marinas, linus.walleij, will.deacon, grant.likely,
	paul.gortmaker, vincent.guittot, nico, davidb, plagnioj, arnd,
	marc.zyngier, rob.herring, vitalya, tglx, linux-arm-kernel,
	rmallon, frank.rowand, sjg, sboyd, linux-kernel, rabin, hsweeten,
	tj

On Fri, Sep 21, 2012 at 11:56:03AM -0400, 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 |   38 ++++++++++++++++++++++++++++++++++++--
>  arch/arm/kernel/head.S        |    4 ++++
>  arch/arm/kernel/setup.c       |    2 +-
>  3 files changed, 41 insertions(+), 3 deletions(-)
> 
> diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> index 88ca206..f3e8f88 100644
> --- a/arch/arm/include/asm/memory.h
> +++ b/arch/arm/include/asm/memory.h
> @@ -154,13 +154,47 @@
>  #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;
> +	phys_addr_t t;
> +
> +#ifndef CONFIG_ARM_LPAE
>  	early_patch_imm8("add", t, x, __pv_offset, 0);
> +#else
> +	unsigned long __tmp;
> +
> +#ifndef __ARMEB__
> +#define PV_PHYS_HIGH	"(__pv_phys_offset + 4)"
> +#else
> +#define PV_PHYS_HIGH	"__pv_phys_offset"
> +#endif
> +
> +	early_patch_stub(
> +	/* type */		PATCH_IMM8,
> +	/* code */
> +		"ldr		%[tmp], =__pv_offset\n"
> +		"ldr		%[tmp], [%[tmp]]\n"
> +		"add		%Q[to], %[from], %[tmp]\n"
> +		"ldr		%[tmp], =" PV_PHYS_HIGH "\n"
> +		"ldr		%[tmp], [%[tmp]]\n"
> +		"mov		%R[to], %[tmp]\n",
> +	/* pad */		4,
> +	/* patch_data */
> +		".long		__pv_offset\n"
> +		"add		%Q[to], %[from], %[imm]\n"
> +		".long	"	PV_PHYS_HIGH "\n"
> +		"mov		%R[to], %[imm]\n",
> +	/* operands */
> +		: [to]	 "=r"	(t),
> +		  [tmp]	 "=&r"	(__tmp)
> +		: [from] "r"	(x),
> +		  [imm]	 "I"	(__IMM8),
> +			 "i"	(&__pv_offset),
> +			 "i"	(&__pv_phys_offset));

So, the actual offset we can apply is:

__pv_phys_offset + __pv_offset

where:

 * the high 32 bits of the address being fixed up are assumed to be 0
   (true, because the kernel is initially always fixed up to an address
   range <4GB)

 * the low 32 bits of __pv_phys_offset are assumed to be 0 (?)

 * the full offset is of the form

        ([..0..]XX[..0..] << 32) | [..0..]YY[..0..] 

Is this intentional?  It seems like a rather weird constraint...  but
it may be sensible.  PAGE_OFFSET is probably 0xc0000000 or 0x80000000,
(so YY can handle that) and the actual RAM above 4GB will likely be
huge and aligned on some enormous boundary in such situations (so that
XX can handle that).

So long as the low RAM alias is not misaligned relative to the high alias
on a finer granularity than 16MB (so that YY = (PAGE_OFFSET +/- the
misalignment) is still a legal immediate), I guess there should not be a
problem.

[...]

Cheers
---Dave

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

* Re: [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching
  2012-09-24 16:31   ` Dave Martin
@ 2012-09-24 16:51     ` Nicolas Pitre
  0 siblings, 0 replies; 29+ messages in thread
From: Nicolas Pitre @ 2012-09-24 16:51 UTC (permalink / raw)
  To: Dave Martin
  Cc: Cyril Chemparathy, Russell King - ARM Linux, Catalin Marinas,
	linus.walleij, Will Deacon, Grant Likely, paul.gortmaker,
	vincent.guittot, davidb, plagnioj, Arnd Bergmann, marc.zyngier,
	rob.herring, vitalya, tglx, linux-arm-kernel, rmallon,
	frank.rowand, sjg, sboyd, linux-kernel, rabin, hsweeten, tj

On Mon, 24 Sep 2012, Dave Martin wrote:

> On Fri, Sep 21, 2012 at 11:56:03AM -0400, 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 |   38 ++++++++++++++++++++++++++++++++++++--
> >  arch/arm/kernel/head.S        |    4 ++++
> >  arch/arm/kernel/setup.c       |    2 +-
> >  3 files changed, 41 insertions(+), 3 deletions(-)
> > 
> > diff --git a/arch/arm/include/asm/memory.h b/arch/arm/include/asm/memory.h
> > index 88ca206..f3e8f88 100644
> > --- a/arch/arm/include/asm/memory.h
> > +++ b/arch/arm/include/asm/memory.h
> > @@ -154,13 +154,47 @@
> >  #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;
> > +	phys_addr_t t;
> > +
> > +#ifndef CONFIG_ARM_LPAE
> >  	early_patch_imm8("add", t, x, __pv_offset, 0);
> > +#else
> > +	unsigned long __tmp;
> > +
> > +#ifndef __ARMEB__
> > +#define PV_PHYS_HIGH	"(__pv_phys_offset + 4)"
> > +#else
> > +#define PV_PHYS_HIGH	"__pv_phys_offset"
> > +#endif
> > +
> > +	early_patch_stub(
> > +	/* type */		PATCH_IMM8,
> > +	/* code */
> > +		"ldr		%[tmp], =__pv_offset\n"
> > +		"ldr		%[tmp], [%[tmp]]\n"
> > +		"add		%Q[to], %[from], %[tmp]\n"
> > +		"ldr		%[tmp], =" PV_PHYS_HIGH "\n"
> > +		"ldr		%[tmp], [%[tmp]]\n"
> > +		"mov		%R[to], %[tmp]\n",
> > +	/* pad */		4,
> > +	/* patch_data */
> > +		".long		__pv_offset\n"
> > +		"add		%Q[to], %[from], %[imm]\n"
> > +		".long	"	PV_PHYS_HIGH "\n"
> > +		"mov		%R[to], %[imm]\n",
> > +	/* operands */
> > +		: [to]	 "=r"	(t),
> > +		  [tmp]	 "=&r"	(__tmp)
> > +		: [from] "r"	(x),
> > +		  [imm]	 "I"	(__IMM8),
> > +			 "i"	(&__pv_offset),
> > +			 "i"	(&__pv_phys_offset));
> 
> So, the actual offset we can apply is:
> 
> __pv_phys_offset + __pv_offset
> 
> where:
> 
>  * the high 32 bits of the address being fixed up are assumed to be 0
>    (true, because the kernel is initially always fixed up to an address
>    range <4GB)

The fixed up address is a virtual address.  So yes, by definition it 
must be <4GB on ARM32.

>  * the low 32 bits of __pv_phys_offset are assumed to be 0 (?)

It is typically representable with a shifted 8 bit immediate but not 
necessarily 0, just like on platforms without LPAE.

>  * the full offset is of the form
> 
>         ([..0..]XX[..0..] << 32) | [..0..]YY[..0..] 
> 
> Is this intentional?  It seems like a rather weird constraint...  but
> it may be sensible.  PAGE_OFFSET is probably 0xc0000000 or 0x80000000,
> (so YY can handle that) and the actual RAM above 4GB will likely be
> huge and aligned on some enormous boundary in such situations (so that
> XX can handle that).
> 
> So long as the low RAM alias is not misaligned relative to the high alias
> on a finer granularity than 16MB (so that YY = (PAGE_OFFSET +/- the
> misalignment) is still a legal immediate), I guess there should not be a
> problem.

There are already similar constraints for the current 
ARM_PATCH_PHYS_VIRT code.  So nothing really new here.


Nicolas

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

end of thread, other threads:[~2012-09-24 16:51 UTC | newest]

Thread overview: 29+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-09-21 15:55 [PATCH v3 RESEND 00/17] LPAE fixes and extensions for Keystone Cyril Chemparathy
2012-09-21 15:55 ` [PATCH v3 RESEND 01/17] ARM: add mechanism for late code patching Cyril Chemparathy
2012-09-22 15:10   ` Nicolas Pitre
2012-09-22 21:41     ` Cyril Chemparathy
2012-09-24 12:06   ` Dave Martin
2012-09-24 14:49     ` Cyril Chemparathy
2012-09-24 15:54       ` Dave Martin
2012-09-21 15:56 ` [PATCH v3 RESEND 02/17] ARM: add self test for runtime patch mechanism Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 03/17] ARM: use late patch framework for phys-virt patching Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 04/17] ARM: LPAE: use phys_addr_t on virt <--> phys conversion Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 05/17] ARM: LPAE: support 64-bit virt_to_phys patching Cyril Chemparathy
2012-09-22 15:24   ` Nicolas Pitre
2012-09-24 16:31   ` Dave Martin
2012-09-24 16:51     ` Nicolas Pitre
2012-09-21 15:56 ` [PATCH v3 RESEND 06/17] ARM: LPAE: use signed arithmetic for mask definitions Cyril Chemparathy
2012-09-24 13:54   ` Russell King - ARM Linux
2012-09-21 15:56 ` [PATCH v3 RESEND 07/17] ARM: LPAE: use phys_addr_t in alloc_init_pud() Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 08/17] ARM: LPAE: use phys_addr_t in free_memmap() Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 09/17] ARM: LPAE: use phys_addr_t for initrd location and size Cyril Chemparathy
2012-09-24 13:38   ` Russell King - ARM Linux
2012-09-24 14:00     ` Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 10/17] ARM: LPAE: use phys_addr_t in switch_mm() Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 11/17] ARM: LPAE: use 64-bit accessors for TTBR registers Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 12/17] ARM: LPAE: define ARCH_LOW_ADDRESS_LIMIT for bootmem Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 13/17] ARM: LPAE: factor out T1SZ and TTBR1 computations Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 14/17] ARM: LPAE: accomodate >32-bit addresses for page table base Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 15/17] ARM: mm: use physical addresses in highmem sanity checks Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 16/17] ARM: mm: cleanup checks for membank overlap with vmalloc area Cyril Chemparathy
2012-09-21 15:56 ` [PATCH v3 RESEND 17/17] ARM: mm: clean up membank size limit checks 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).