All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 0/8] arm64: Add a compat vDSO
@ 2016-09-08 13:53 Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 1/8] arm64: Refactor vDSO setup Kevin Brodsky
                   ` (8 more replies)
  0 siblings, 9 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Hi,

This series adds support for a compat (AArch32) vDSO, providing two
userspace functionalities to compat processes:

* Time "virtual" syscalls (gettimeofday and clock_gettime). The
  implementation is an adaptation of the arm vDSO (vgettimeofday.c),
  using the same the data page as the 64-bit vDSO.

* sigreturn trampolines, following the example of the 64-bit vDSO
  (sigreturn.S), but slightly more complicated because we provide A32
  and T32 variants for both sigreturn and rt_sigreturn.

The first point brings the performance improvement expected of a vDSO,
by implementing syscalls directly in userspace. The second point allows
us to get rid of the compat vector page, at the expense of the kuser
helpers (this is one reason for not enabling the compat vDSO by
default).

Unfortunately, this time we cannot escape using a 32-bit toolchain. To
build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and*
CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler.
Failure to do so will not prevent building the kernel, but a warning
will be printed and the compat vDSO will not be built.


The last patch requires my Makefile fix [1] to apply. I pushed the
series on top of this patch on pdsw-git:

  git at pdsw-git.cambridge.arm.com:users/kevbro01/linux compat-vdso

I have only tested the series with a 64-bit userspace (+ 32-bit glibc).
Testing it with a 32-bit userspace would be very welcome.

Thanks,
Kevin

[1]: "arm64: fix vdso-offsets.h dependency"
     http://lists.infradead.org/pipermail/linux-arm-kernel/2016-April/422307.html

Kevin Brodsky (8):
  arm64: Refactor vDSO setup
  arm64: compat: Add time-related syscall numbers
  arm64: compat: Expose offset to registers in sigframes
  arm64: compat: Add a 32-bit vDSO
  arm64: compat: 32-bit vDSO setup
  arm64: elf: Set AT_SYSINFO_EHDR in compat processes
  arm64: compat: Use vDSO sigreturn trampolines if available
  arm64: Wire up and expose the new compat vDSO

 arch/arm64/Kconfig                       |  20 +++
 arch/arm64/Makefile                      |  20 ++-
 arch/arm64/include/asm/elf.h             |  13 +-
 arch/arm64/include/asm/signal32.h        |  46 +++++
 arch/arm64/include/asm/unistd.h          |   2 +
 arch/arm64/include/asm/vdso.h            |   3 +
 arch/arm64/kernel/Makefile               |   9 +-
 arch/arm64/kernel/asm-offsets.c          |  13 ++
 arch/arm64/kernel/signal32.c             |  61 ++-----
 arch/arm64/kernel/vdso.c                 | 196 +++++++++++++--------
 arch/arm64/kernel/vdso32/Makefile        | 120 +++++++++++++
 arch/arm64/kernel/vdso32/sigreturn.S     |  82 +++++++++
 arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
 15 files changed, 876 insertions(+), 133 deletions(-)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

-- 
2.8.2

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

* [PATCH 1/8] arm64: Refactor vDSO setup
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 2/8] arm64: compat: Add time-related syscall numbers Kevin Brodsky
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Move the logic for setting up mappings and pages for the vDSO into
static functions with a clear interface. This will allow to reuse the
setup code for the future compat vDSO.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/kernel/vdso.c | 174 ++++++++++++++++++++++++++---------------------
 1 file changed, 97 insertions(+), 77 deletions(-)

diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index 97bc68f4c689..b9a1268c21c6 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -36,9 +36,11 @@
 #include <asm/vdso.h>
 #include <asm/vdso_datapage.h>
 
-extern char vdso_start, vdso_end;
-static unsigned long vdso_pages;
-static struct page **vdso_pagelist;
+struct vdso_mappings {
+	unsigned long num_pages;
+	struct page **pages;
+	struct vm_special_mapping data_mapping, code_mapping;
+};
 
 /*
  * The vDSO data page.
@@ -49,6 +51,92 @@ static union {
 } vdso_data_store __page_aligned_data;
 struct vdso_data *vdso_data = &vdso_data_store.data;
 
+static int __init setup_vdso_mappings(const char *name,
+				      const char *code_start,
+				      const char *code_end,
+				      struct vdso_mappings *mappings)
+{
+	unsigned long i, num_pages;
+	struct page **pages;
+
+	if (memcmp(code_start, "\177ELF", 4)) {
+		pr_err("%s is not a valid ELF object!\n", name);
+		return -EINVAL;
+	}
+
+	num_pages = (code_end - code_start) >> PAGE_SHIFT;
+	pr_info("%s: %ld pages (%ld code @ %p, %ld data @ %p)\n",
+		name, num_pages + 1, num_pages, code_start, 1L, vdso_data);
+
+	/* Allocate the vDSO code pages, plus a page for the data. */
+	pages = kcalloc(num_pages + 1, sizeof(struct page *), GFP_KERNEL);
+	if (pages == NULL)
+		return -ENOMEM;
+
+	/* Grab the vDSO data page. */
+	pages[0] = virt_to_page(vdso_data);
+
+	/* Grab the vDSO code pages. */
+	for (i = 0; i < num_pages; i++)
+		pages[i + 1] = virt_to_page(code_start + i * PAGE_SIZE);
+
+	/* Populate the special mapping structures */
+	mappings->data_mapping = (struct vm_special_mapping) {
+		.name	= "[vvar]",
+		.pages	= &pages[0],
+	};
+
+	mappings->code_mapping = (struct vm_special_mapping) {
+		.name	= "[vdso]",
+		.pages	= &pages[1],
+	};
+
+	mappings->num_pages = num_pages;
+	mappings->pages = pages;
+	return 0;
+}
+
+static int setup_vdso_pages(const struct vdso_mappings *mappings)
+{
+	struct mm_struct *mm = current->mm;
+	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
+	void *ret;
+
+	vdso_text_len = mappings->num_pages << PAGE_SHIFT;
+	/* Be sure to map the data page */
+	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
+
+	down_write(&mm->mmap_sem);
+	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
+	if (IS_ERR_VALUE(vdso_base)) {
+		ret = ERR_PTR(vdso_base);
+		goto up_fail;
+	}
+	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
+				       VM_READ|VM_MAYREAD,
+				       &mappings->data_mapping);
+	if (IS_ERR(ret))
+		goto up_fail;
+
+	vdso_base += PAGE_SIZE;
+	mm->context.vdso = (void *)vdso_base;
+	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
+				       VM_READ|VM_EXEC|
+				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
+				       &mappings->code_mapping);
+	if (IS_ERR(ret))
+		goto up_fail;
+
+
+	up_write(&mm->mmap_sem);
+	return 0;
+
+up_fail:
+	mm->context.vdso = NULL;
+	up_write(&mm->mmap_sem);
+	return PTR_ERR(ret);
+}
+
 #ifdef CONFIG_COMPAT
 /*
  * Create and map the vectors page for AArch32 tasks.
@@ -109,89 +197,21 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
 }
 #endif /* CONFIG_COMPAT */
 
-static struct vm_special_mapping vdso_spec[2];
+extern char vdso_start, vdso_end;
+
+static struct vdso_mappings vdso_mappings;
 
 static int __init vdso_init(void)
 {
-	int i;
-
-	if (memcmp(&vdso_start, "\177ELF", 4)) {
-		pr_err("vDSO is not a valid ELF object!\n");
-		return -EINVAL;
-	}
-
-	vdso_pages = (&vdso_end - &vdso_start) >> PAGE_SHIFT;
-	pr_info("vdso: %ld pages (%ld code @ %p, %ld data @ %p)\n",
-		vdso_pages + 1, vdso_pages, &vdso_start, 1L, vdso_data);
-
-	/* Allocate the vDSO pagelist, plus a page for the data. */
-	vdso_pagelist = kcalloc(vdso_pages + 1, sizeof(struct page *),
-				GFP_KERNEL);
-	if (vdso_pagelist == NULL)
-		return -ENOMEM;
-
-	/* Grab the vDSO data page. */
-	vdso_pagelist[0] = virt_to_page(vdso_data);
-
-	/* Grab the vDSO code pages. */
-	for (i = 0; i < vdso_pages; i++)
-		vdso_pagelist[i + 1] = virt_to_page(&vdso_start + i * PAGE_SIZE);
-
-	/* Populate the special mapping structures */
-	vdso_spec[0] = (struct vm_special_mapping) {
-		.name	= "[vvar]",
-		.pages	= vdso_pagelist,
-	};
-
-	vdso_spec[1] = (struct vm_special_mapping) {
-		.name	= "[vdso]",
-		.pages	= &vdso_pagelist[1],
-	};
-
-	return 0;
+	return setup_vdso_mappings("vdso", &vdso_start, &vdso_end,
+				   &vdso_mappings);
 }
 arch_initcall(vdso_init);
 
 int arch_setup_additional_pages(struct linux_binprm *bprm,
 				int uses_interp)
 {
-	struct mm_struct *mm = current->mm;
-	unsigned long vdso_base, vdso_text_len, vdso_mapping_len;
-	void *ret;
-
-	vdso_text_len = vdso_pages << PAGE_SHIFT;
-	/* Be sure to map the data page */
-	vdso_mapping_len = vdso_text_len + PAGE_SIZE;
-
-	down_write(&mm->mmap_sem);
-	vdso_base = get_unmapped_area(NULL, 0, vdso_mapping_len, 0, 0);
-	if (IS_ERR_VALUE(vdso_base)) {
-		ret = ERR_PTR(vdso_base);
-		goto up_fail;
-	}
-	ret = _install_special_mapping(mm, vdso_base, PAGE_SIZE,
-				       VM_READ|VM_MAYREAD,
-				       &vdso_spec[0]);
-	if (IS_ERR(ret))
-		goto up_fail;
-
-	vdso_base += PAGE_SIZE;
-	mm->context.vdso = (void *)vdso_base;
-	ret = _install_special_mapping(mm, vdso_base, vdso_text_len,
-				       VM_READ|VM_EXEC|
-				       VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
-				       &vdso_spec[1]);
-	if (IS_ERR(ret))
-		goto up_fail;
-
-
-	up_write(&mm->mmap_sem);
-	return 0;
-
-up_fail:
-	mm->context.vdso = NULL;
-	up_write(&mm->mmap_sem);
-	return PTR_ERR(ret);
+	return setup_vdso_pages(&vdso_mappings);
 }
 
 /*
-- 
2.8.2

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

* [PATCH 2/8] arm64: compat: Add time-related syscall numbers
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 1/8] arm64: Refactor vDSO setup Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 3/8] arm64: compat: Expose offset to registers in sigframes Kevin Brodsky
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

They will be used by the future compat vDSO.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/unistd.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/arch/arm64/include/asm/unistd.h b/arch/arm64/include/asm/unistd.h
index 41e58fe3c041..b57bae526d3f 100644
--- a/arch/arm64/include/asm/unistd.h
+++ b/arch/arm64/include/asm/unistd.h
@@ -34,8 +34,10 @@
 #define __NR_compat_exit		1
 #define __NR_compat_read		3
 #define __NR_compat_write		4
+#define __NR_compat_gettimeofday	78
 #define __NR_compat_sigreturn		119
 #define __NR_compat_rt_sigreturn	173
+#define __NR_compat_clock_gettime	263
 
 /*
  * The following SVCs are ARM private.
-- 
2.8.2

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

* [PATCH 3/8] arm64: compat: Expose offset to registers in sigframes
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 1/8] arm64: Refactor vDSO setup Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 2/8] arm64: compat: Add time-related syscall numbers Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 4/8] arm64: compat: Add a 32-bit vDSO Kevin Brodsky
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

This will be needed to provide debug information (CFI/unwind tables)
in compat sigreturn trampolines, part of the future compat vDSO.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/signal32.h | 46 +++++++++++++++++++++++++++++++++++++++
 arch/arm64/kernel/asm-offsets.c   | 13 +++++++++++
 arch/arm64/kernel/signal32.c      | 46 ---------------------------------------
 3 files changed, 59 insertions(+), 46 deletions(-)

diff --git a/arch/arm64/include/asm/signal32.h b/arch/arm64/include/asm/signal32.h
index eeaa97559bab..ee0def038182 100644
--- a/arch/arm64/include/asm/signal32.h
+++ b/arch/arm64/include/asm/signal32.h
@@ -20,6 +20,52 @@
 #ifdef CONFIG_COMPAT
 #include <linux/compat.h>
 
+struct compat_sigcontext {
+	/* We always set these two fields to 0 */
+	compat_ulong_t			trap_no;
+	compat_ulong_t			error_code;
+
+	compat_ulong_t			oldmask;
+	compat_ulong_t			arm_r0;
+	compat_ulong_t			arm_r1;
+	compat_ulong_t			arm_r2;
+	compat_ulong_t			arm_r3;
+	compat_ulong_t			arm_r4;
+	compat_ulong_t			arm_r5;
+	compat_ulong_t			arm_r6;
+	compat_ulong_t			arm_r7;
+	compat_ulong_t			arm_r8;
+	compat_ulong_t			arm_r9;
+	compat_ulong_t			arm_r10;
+	compat_ulong_t			arm_fp;
+	compat_ulong_t			arm_ip;
+	compat_ulong_t			arm_sp;
+	compat_ulong_t			arm_lr;
+	compat_ulong_t			arm_pc;
+	compat_ulong_t			arm_cpsr;
+	compat_ulong_t			fault_address;
+};
+
+struct compat_ucontext {
+	compat_ulong_t			uc_flags;
+	compat_uptr_t			uc_link;
+	compat_stack_t			uc_stack;
+	struct compat_sigcontext	uc_mcontext;
+	compat_sigset_t			uc_sigmask;
+	int		__unused[32 - (sizeof (compat_sigset_t) / sizeof (int))];
+	compat_ulong_t	uc_regspace[128] __attribute__((__aligned__(8)));
+};
+
+struct compat_sigframe {
+	struct compat_ucontext	uc;
+	compat_ulong_t		retcode[2];
+};
+
+struct compat_rt_sigframe {
+	struct compat_siginfo info;
+	struct compat_sigframe sig;
+};
+
 #define AARCH32_KERN_SIGRET_CODE_OFFSET	0x500
 
 extern const compat_ulong_t aarch32_sigret_code[6];
diff --git a/arch/arm64/kernel/asm-offsets.c b/arch/arm64/kernel/asm-offsets.c
index 3ae6b310ac9b..82e60cbcad03 100644
--- a/arch/arm64/kernel/asm-offsets.c
+++ b/arch/arm64/kernel/asm-offsets.c
@@ -24,6 +24,7 @@
 #include <linux/kvm_host.h>
 #include <asm/thread_info.h>
 #include <asm/memory.h>
+#include <asm/signal32.h>
 #include <asm/smp_plat.h>
 #include <asm/suspend.h>
 #include <asm/vdso_datapage.h>
@@ -61,6 +62,18 @@ int main(void)
   DEFINE(S_SYSCALLNO,		offsetof(struct pt_regs, syscallno));
   DEFINE(S_FRAME_SIZE,		sizeof(struct pt_regs));
   BLANK();
+#ifdef CONFIG_COMPAT
+  DEFINE(COMPAT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  DEFINE(COMPAT_RT_SIGFRAME_REGS_OFFSET,
+				offsetof(struct compat_rt_sigframe, sig) +
+				offsetof(struct compat_sigframe, uc) +
+				offsetof(struct compat_ucontext, uc_mcontext) +
+				offsetof(struct compat_sigcontext, arm_r0));
+  BLANK();
+#endif
   DEFINE(MM_CONTEXT_ID,		offsetof(struct mm_struct, context.id.counter));
   BLANK();
   DEFINE(VMA_VM_MM,		offsetof(struct vm_area_struct, vm_mm));
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index b7063de792f7..9de7d128e0e0 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -29,42 +29,6 @@
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
 
-struct compat_sigcontext {
-	/* We always set these two fields to 0 */
-	compat_ulong_t			trap_no;
-	compat_ulong_t			error_code;
-
-	compat_ulong_t			oldmask;
-	compat_ulong_t			arm_r0;
-	compat_ulong_t			arm_r1;
-	compat_ulong_t			arm_r2;
-	compat_ulong_t			arm_r3;
-	compat_ulong_t			arm_r4;
-	compat_ulong_t			arm_r5;
-	compat_ulong_t			arm_r6;
-	compat_ulong_t			arm_r7;
-	compat_ulong_t			arm_r8;
-	compat_ulong_t			arm_r9;
-	compat_ulong_t			arm_r10;
-	compat_ulong_t			arm_fp;
-	compat_ulong_t			arm_ip;
-	compat_ulong_t			arm_sp;
-	compat_ulong_t			arm_lr;
-	compat_ulong_t			arm_pc;
-	compat_ulong_t			arm_cpsr;
-	compat_ulong_t			fault_address;
-};
-
-struct compat_ucontext {
-	compat_ulong_t			uc_flags;
-	compat_uptr_t			uc_link;
-	compat_stack_t			uc_stack;
-	struct compat_sigcontext	uc_mcontext;
-	compat_sigset_t			uc_sigmask;
-	int		__unused[32 - (sizeof (compat_sigset_t) / sizeof (int))];
-	compat_ulong_t	uc_regspace[128] __attribute__((__aligned__(8)));
-};
-
 struct compat_vfp_sigframe {
 	compat_ulong_t	magic;
 	compat_ulong_t	size;
@@ -91,16 +55,6 @@ struct compat_aux_sigframe {
 	unsigned long			end_magic;
 } __attribute__((__aligned__(8)));
 
-struct compat_sigframe {
-	struct compat_ucontext	uc;
-	compat_ulong_t		retcode[2];
-};
-
-struct compat_rt_sigframe {
-	struct compat_siginfo info;
-	struct compat_sigframe sig;
-};
-
 #define _BLOCKABLE (~(sigmask(SIGKILL) | sigmask(SIGSTOP)))
 
 static inline int put_sigset_t(compat_sigset_t __user *uset, sigset_t *set)
-- 
2.8.2

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

* [PATCH 4/8] arm64: compat: Add a 32-bit vDSO
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (2 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 3/8] arm64: compat: Expose offset to registers in sigframes Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 5/8] arm64: compat: 32-bit vDSO setup Kevin Brodsky
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Provide the files necessary for building a compat (AArch32) vDSO in
kernel/vdso32.

This is mostly an adaptation of the arm vDSO. The most significant
change in vgettimeofday.c is the use of the arm64 vdso_data struct,
allowing the vDSO data page to be shared between the 32 and 64-bit
vDSOs.

In addition to the time functions, sigreturn trampolines are also
provided, aiming at replacing those in the vector page. To improve
debugging, CFI and unwinding directives are used, based on glibc's
implementation. Symbol offsets are made available to the kernel using
the same method as the 64-bit vDSO.

There is unfortunately an important caveat to all this: we cannot get
away with hand-coding 32-bit instructions like in kernel/kuser32.S,
this time we really need a 32-bit compiler. The compat vDSO Makefile
relies on CROSS_COMPILE_ARM32 to provide a 32-bit compiler,
appropriate logic will be added to the arm64 Makefile later on to
ensure that an attempt to build the compat vDSO is made only if this
variable has been set properly.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/kernel/vdso32/Makefile        | 120 +++++++++++++
 arch/arm64/kernel/vdso32/sigreturn.S     |  82 +++++++++
 arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
 arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
 arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
 5 files changed, 626 insertions(+)
 create mode 100644 arch/arm64/kernel/vdso32/Makefile
 create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.S
 create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
 create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c

diff --git a/arch/arm64/kernel/vdso32/Makefile b/arch/arm64/kernel/vdso32/Makefile
new file mode 100644
index 000000000000..3c14ef17a2b7
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/Makefile
@@ -0,0 +1,120 @@
+#
+# Building a vDSO image for AArch32.
+#
+# Author: Kevin Brodsky <kevin.brodsky@arm.com>
+# A mix between the arm64 and arm vDSO Makefiles.
+
+CC_ARM32 := $(CROSS_COMPILE_ARM32)gcc
+
+cc32-ldoption = $(call try-run,\
+        $(CC_ARM32) $(1) -nostdlib -x c /dev/null -o "$$TMP",$(1),$(2))
+
+# Borrow vdsomunge.c from the arm vDSO
+munge := arch/arm/vdso/vdsomunge
+hostprogs-y := $(srctree)/$(munge)
+
+c-obj-vdso := vgettimeofday.o
+asm-obj-vdso := sigreturn.o
+
+# Build rules
+targets := $(c-obj-vdso) $(asm-obj-vdso) vdso.so vdso.so.dbg vdso.so.raw
+c-obj-vdso := $(addprefix $(obj)/, $(c-obj-vdso))
+asm-obj-vdso := $(addprefix $(obj)/, $(asm-obj-vdso))
+obj-vdso := $(c-obj-vdso) $(asm-obj-vdso)
+
+ccflags-y := -fPIC -fno-common -fno-builtin -fno-stack-protector
+ccflags-y += -DDISABLE_BRANCH_PROFILING
+
+# Force -O2 to avoid libgcc dependencies
+VDSO_CFLAGS := -march=armv8-a -O2
+# Import some useful flags from arch/arm/Makefile
+VDSO_CFLAGS += -mabi=aapcs-linux -mfloat-abi=soft -funwind-tables
+# The 32-bit compiler does not provide 128-bit integers, which are used in
+# some headers that are indirectly included from the vDSO code.
+# This hack makes the compiler happy and should trigger a warning/error if
+# variables of such type are referenced.
+VDSO_CFLAGS += -D__uint128_t='void*'
+# Silence some warnings coming from headers that operate on long's
+VDSO_CFLAGS += -Wno-shift-count-overflow -Wno-int-to-pointer-cast
+
+# We need to use the global flags to compile the vDSO files. However some flags
+# inherited from either the top-level or the arm64 Makefile are not appropriate
+# for the 32-bit compiler, this function takes care of changing them as
+# appropriate.
+sanitize_flags = \
+        $(subst $(shell $(CC) -print-file-name=include), \
+                $(shell $(CC_ARM32) -print-file-name=include), \
+        $(filter-out -pg -mgeneral-regs-only -mpc-relative-literal-loads \
+                     -fno-asynchronous-unwind-tables, \
+        $(1)))
+
+VDSO_LDFLAGS := -Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1
+VDSO_LDFLAGS += -Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
+VDSO_LDFLAGS += -nostdlib -shared -mfloat-abi=soft
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--hash-style=sysv)
+VDSO_LDFLAGS += $(call cc32-ldoption, -Wl$(comma)--build-id)
+VDSO_LDFLAGS += $(call cc32-ldoption, -fuse-ld=bfd)
+
+obj-y += vdso.o
+extra-y += vdso.lds
+CPPFLAGS_vdso.lds += -P -C -U$(ARCH)
+
+CFLAGS_REMOVE_vdso.o = -pg
+
+# Disable gcov profiling for VDSO code
+GCOV_PROFILE := n
+
+# Force dependency (incbin is bad)
+$(obj)/vdso.o: $(obj)/vdso.so
+
+# Link rule for the .so file, .lds has to be first
+$(obj)/vdso.so.raw: $(src)/vdso.lds $(obj-vdso) FORCE
+	$(call if_changed,vdsold)
+
+$(obj)/vdso.so.dbg: $(obj)/vdso.so.raw $(objtree)/$(munge) FORCE
+	$(call if_changed,vdsomunge)
+
+# Strip rule for the .so file
+$(obj)/%.so: OBJCOPYFLAGS := -S
+$(obj)/%.so: $(obj)/%.so.dbg FORCE
+	$(call if_changed,objcopy)
+
+# Generate vDSO offsets using helper script (borrowed from the 64-bit vDSO)
+gen-vdsosym := $(srctree)/$(src)/../vdso/gen_vdso_offsets.sh
+quiet_cmd_vdsosym = VDSOSYM $@
+# The AArch64 nm should be able to read an AArch32 binary
+define cmd_vdsosym
+	$(NM) $< | $(gen-vdsosym) | LC_ALL=C sort > $@
+endef
+
+include/generated/vdso32-offsets.h: $(obj)/vdso.so.dbg FORCE
+	$(call if_changed,vdsosym)
+
+# Compilation rules for the vDSO sources
+$(c-obj-vdso): %.o: %.c FORCE
+	$(call if_changed_dep,vdsocc)
+$(asm-obj-vdso): %.o: %.S FORCE
+	$(call if_changed_dep,vdsoas)
+
+# Actual build commands
+quiet_cmd_vdsold = VDSOL   $@
+      cmd_vdsold = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+                   $(VDSO_LDFLAGS) -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
+quiet_cmd_vdsocc = VDSOC   $@
+      cmd_vdsocc = $(CC_ARM32) $(call sanitize_flags,$(c_flags)) \
+                   $(VDSO_CFLAGS) -c -o $@ $<
+quiet_cmd_vdsoas = VDSOA   $@
+      cmd_vdsoas = $(CC_ARM32) $(call sanitize_flags, $(a_flags)) -c -o $@ $<
+
+quiet_cmd_vdsomunge = MUNGE   $@
+      cmd_vdsomunge = $(objtree)/$(munge) $< $@
+
+# Install commands for the unstripped file
+quiet_cmd_vdso_install = INSTALL $@
+      cmd_vdso_install = cp $(obj)/$@.dbg $(MODLIB)/vdso/vdso32.so
+
+vdso.so: $(obj)/vdso.so.dbg
+	@mkdir -p $(MODLIB)/vdso
+	$(call cmd,vdso_install)
+
+vdso_install: vdso.so
diff --git a/arch/arm64/kernel/vdso32/sigreturn.S b/arch/arm64/kernel/vdso32/sigreturn.S
new file mode 100644
index 000000000000..8a895055992b
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/sigreturn.S
@@ -0,0 +1,82 @@
+/*
+ * Sigreturn trampolines for returning from a signal when the SA_RESTORER
+ * flag is not set.
+ *
+ * Copyright (C) 2016 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/>.
+ *
+ * Based on glibc's arm sa_restorer. While this is not strictly necessary, we
+ * provide both A32 and T32 versions, in accordance with the arm sigreturn
+ * code.
+ */
+
+#include <linux/linkage.h>
+#include <asm/asm-offsets.h>
+#include <asm/unistd.h>
+
+.macro cfi_regs offset
+	.cfi_def_cfa sp, 0
+	.cfi_offset r0, \offset + 0 * 4
+	.cfi_offset r1, \offset + 1 * 4
+	.cfi_offset r2, \offset + 2 * 4
+	.cfi_offset r3, \offset + 3 * 4
+	.cfi_offset r4, \offset + 4 * 4
+	.cfi_offset r5, \offset + 5 * 4
+	.cfi_offset r6, \offset + 6 * 4
+	.cfi_offset r7, \offset + 7 * 4
+	.cfi_offset r8, \offset + 8 * 4
+	.cfi_offset r9, \offset + 9 * 4
+	.cfi_offset r10, \offset + 10 * 4
+	.cfi_offset r11, \offset + 11 * 4
+	.cfi_offset r12, \offset + 12 * 4
+	.cfi_offset r13, \offset + 13 * 4
+	.cfi_offset r14, \offset + 14 * 4
+	.cfi_offset r15, \offset + 15 * 4
+.endm
+
+.macro sigreturn_trampoline name, syscall, regs_offset
+	.fnstart
+	.save {r0-r15}
+	.pad #\regs_offset
+ENTRY(\name)
+	.cfi_startproc
+	.cfi_signal_frame
+	cfi_regs \regs_offset
+	mov	r7, #\syscall
+	svc	#0
+	.fnend
+	.cfi_endproc
+/*
+ * We would like to use ENDPROC, but the macro uses @ which is a comment symbol
+ * for arm assemblers, so directly use .type with % instead.
+ */
+	.type \name, %function
+END(\name)
+.endm
+
+	.text
+
+	.arm
+	sigreturn_trampoline __kernel_sigreturn_arm, __NR_compat_sigreturn, \
+			     COMPAT_SIGFRAME_REGS_OFFSET
+
+	sigreturn_trampoline __kernel_rt_sigreturn_arm, __NR_compat_rt_sigreturn, \
+			     COMPAT_RT_SIGFRAME_REGS_OFFSET
+
+	.thumb
+	sigreturn_trampoline __kernel_sigreturn_thumb, __NR_compat_sigreturn, \
+			     COMPAT_SIGFRAME_REGS_OFFSET
+
+	sigreturn_trampoline __kernel_rt_sigreturn_thumb, __NR_compat_rt_sigreturn, \
+			     COMPAT_RT_SIGFRAME_REGS_OFFSET
diff --git a/arch/arm64/kernel/vdso32/vdso.S b/arch/arm64/kernel/vdso32/vdso.S
new file mode 100644
index 000000000000..fe19ff70eb76
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.S
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ */
+
+#include <linux/init.h>
+#include <linux/linkage.h>
+#include <linux/const.h>
+#include <asm/page.h>
+
+	.globl vdso32_start, vdso32_end
+	.section .rodata
+	.balign PAGE_SIZE
+vdso32_start:
+	.incbin "arch/arm64/kernel/vdso32/vdso.so"
+	.balign PAGE_SIZE
+vdso32_end:
+
+	.previous
diff --git a/arch/arm64/kernel/vdso32/vdso.lds.S b/arch/arm64/kernel/vdso32/vdso.lds.S
new file mode 100644
index 000000000000..95abcc0dd37e
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vdso.lds.S
@@ -0,0 +1,98 @@
+/*
+ * Adapted from arm64 version.
+ *
+ * GNU linker script for the VDSO library.
+ *
+ * Copyright (C) 2012 ARM Limited
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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/>.
+ *
+ * Author: Will Deacon <will.deacon@arm.com>
+ * Heavily based on the vDSO linker scripts for other archs.
+ */
+
+#include <linux/const.h>
+#include <asm/page.h>
+#include <asm/vdso.h>
+
+OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
+OUTPUT_ARCH(arm)
+
+SECTIONS
+{
+	HIDDEN(_vdso_data = . - PAGE_SIZE);
+	. = VDSO_LBASE + SIZEOF_HEADERS;
+
+	.hash		: { *(.hash) }			:text
+	.gnu.hash	: { *(.gnu.hash) }
+	.dynsym		: { *(.dynsym) }
+	.dynstr		: { *(.dynstr) }
+	.gnu.version	: { *(.gnu.version) }
+	.gnu.version_d	: { *(.gnu.version_d) }
+	.gnu.version_r	: { *(.gnu.version_r) }
+
+	.note		: { *(.note.*) }		:text	:note
+
+
+	.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text	:eh_frame_hdr
+	.eh_frame	: { KEEP (*(.eh_frame)) }	:text
+
+	.dynamic	: { *(.dynamic) }		:text	:dynamic
+
+	.rodata		: { *(.rodata*) }		:text
+
+	.text		: { *(.text*) }			:text	=0xe7f001f2
+
+	.got		: { *(.got) }
+	.rel.plt	: { *(.rel.plt) }
+
+	/DISCARD/	: {
+		*(.note.GNU-stack)
+		*(.data .data.* .gnu.linkonce.d.* .sdata*)
+		*(.bss .sbss .dynbss .dynsbss)
+	}
+}
+
+/*
+ * We must supply the ELF program headers explicitly to get just one
+ * PT_LOAD segment, and set the flags explicitly to make segments read-only.
+ */
+PHDRS
+{
+	text		PT_LOAD		FLAGS(5) FILEHDR PHDRS; /* PF_R|PF_X */
+	dynamic		PT_DYNAMIC	FLAGS(4);		/* PF_R */
+	note		PT_NOTE		FLAGS(4);		/* PF_R */
+	eh_frame_hdr	PT_GNU_EH_FRAME;
+}
+
+VERSION
+{
+	LINUX_2.6 {
+	global:
+		__vdso_clock_gettime;
+		__vdso_gettimeofday;
+		__kernel_sigreturn_arm;
+		__kernel_sigreturn_thumb;
+		__kernel_rt_sigreturn_arm;
+		__kernel_rt_sigreturn_thumb;
+	local: *;
+	};
+}
+
+/*
+ * Make the sigreturn code visible to the kernel.
+ */
+VDSO_compat_sigreturn_arm	= __kernel_sigreturn_arm;
+VDSO_compat_sigreturn_thumb	= __kernel_sigreturn_thumb;
+VDSO_compat_rt_sigreturn_arm	= __kernel_rt_sigreturn_arm;
+VDSO_compat_rt_sigreturn_thumb	= __kernel_rt_sigreturn_thumb;
diff --git a/arch/arm64/kernel/vdso32/vgettimeofday.c b/arch/arm64/kernel/vdso32/vgettimeofday.c
new file mode 100644
index 000000000000..7e617677d8fd
--- /dev/null
+++ b/arch/arm64/kernel/vdso32/vgettimeofday.c
@@ -0,0 +1,294 @@
+/*
+ * Copyright 2015 Mentor Graphics Corporation.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; version 2 of the
+ * License.
+ *
+ * This program is distributed in the hope that 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/clocksource.h>
+#include <linux/compiler.h>
+#include <linux/time.h>
+#include <asm/barrier.h>
+#include <asm/unistd.h>
+#include <asm/vdso_datapage.h>
+
+/*
+ * We use the hidden visibility to prevent the compiler from generating a GOT
+ * relocation. Not only is going through a GOT useless (the entry couldn't and
+ * musn't be overriden by another library), it does not even work: the linker
+ * cannot generate an absolute address to the data page.
+ *
+ * With the hidden visibility, the compiler simply generates a PC-relative
+ * relocation (R_ARM_REL32), and this is what we need.
+ */
+extern const struct vdso_data _vdso_data __attribute__((visibility("hidden")));
+
+static inline const struct vdso_data *get_vdso_data(void)
+{
+	const struct vdso_data *ret;
+	/*
+	 * This simply puts &_vdso_data into ret. The reason why we don't use
+	 * "ret = &_vdso_data" is that the compiler tends to optimise this in a
+	 * very suboptimal way: instead of keeping &_vdso_data in a register,
+	 * it goes through a relocation almost every time _vdso_data must be
+	 * accessed (even in subfunctions). This is both time and space
+	 * consuming: each relocation uses a word in the code section, and it
+	 * has to be loaded at runtime.
+	 *
+	 * This trick hides the assignment from the compiler. Since it cannot
+	 * track where the pointer comes from, it will only use one relocation
+	 * where get_vdso_data() is called, and then keep the result in a
+	 * register.
+	 */
+	asm("mov %0, %1" : "=r"(ret) : "r"(&_vdso_data));
+	return ret;
+}
+
+static notrace u32 __vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq;
+repeat:
+	seq = ACCESS_ONCE(vdata->tb_seq_count);
+	if (seq & 1) {
+		cpu_relax();
+		goto repeat;
+	}
+	return seq;
+}
+
+static notrace u32 vdso_read_begin(const struct vdso_data *vdata)
+{
+	u32 seq;
+
+	seq = __vdso_read_begin(vdata);
+
+	smp_rmb(); /* Pairs with smp_wmb in vdso_write_end */
+	return seq;
+}
+
+static notrace int vdso_read_retry(const struct vdso_data *vdata, u32 start)
+{
+	smp_rmb(); /* Pairs with smp_wmb in vdso_write_begin */
+	return vdata->tb_seq_count != start;
+}
+
+/*
+ * Note: only AEABI is supported by the compat layer, we can assume AEABI
+ * syscall conventions are used.
+ */
+static notrace long clock_gettime_fallback(clockid_t _clkid,
+					   struct timespec *_ts)
+{
+	register struct timespec *ts asm("r1") = _ts;
+	register clockid_t clkid asm("r0") = _clkid;
+	register long ret asm ("r0");
+	register long nr asm("r7") = __NR_compat_clock_gettime;
+
+	asm volatile(
+	"	svc #0\n"
+	: "=r" (ret)
+	: "r" (clkid), "r" (ts), "r" (nr)
+	: "memory");
+
+	return ret;
+}
+
+static notrace int do_realtime_coarse(struct timespec *ts,
+				      const struct vdso_data *vdata)
+{
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	return 0;
+}
+
+static notrace int do_monotonic_coarse(struct timespec *ts,
+				       const struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		ts->tv_sec = vdata->xtime_coarse_sec;
+		ts->tv_nsec = vdata->xtime_coarse_nsec;
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	timespec_add_ns(ts, tomono.tv_nsec);
+
+	return 0;
+}
+
+static notrace u64 get_ns(const struct vdso_data *vdata)
+{
+	u64 cycle_delta;
+	u64 cycle_now;
+	u64 nsec;
+
+	/* AArch32 implementation of arch_counter_get_cntvct() */
+	isb();
+	asm volatile("mrrc p15, 1, %Q0, %R0, c14" : "=r" (cycle_now));
+
+	/* The virtual counter provides 56 significant bits. */
+	cycle_delta = (cycle_now - vdata->cs_cycle_last) & CLOCKSOURCE_MASK(56);
+
+	nsec = (cycle_delta * vdata->cs_mult) + vdata->xtime_clock_nsec;
+	nsec >>= vdata->cs_shift;
+
+	return nsec;
+}
+
+static notrace int do_realtime(struct timespec *ts,
+			       const struct vdso_data *vdata)
+{
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs);
+
+	return 0;
+}
+
+static notrace int do_monotonic(struct timespec *ts,
+				const struct vdso_data *vdata)
+{
+	struct timespec tomono;
+	u64 nsecs;
+	u32 seq;
+
+	do {
+		seq = vdso_read_begin(vdata);
+
+		if (vdata->use_syscall)
+			return -1;
+
+		ts->tv_sec = vdata->xtime_clock_sec;
+		nsecs = get_ns(vdata);
+
+		tomono.tv_sec = vdata->wtm_clock_sec;
+		tomono.tv_nsec = vdata->wtm_clock_nsec;
+
+	} while (vdso_read_retry(vdata, seq));
+
+	ts->tv_sec += tomono.tv_sec;
+	ts->tv_nsec = 0;
+	timespec_add_ns(ts, nsecs + tomono.tv_nsec);
+
+	return 0;
+}
+
+notrace int __vdso_clock_gettime(clockid_t clkid, struct timespec *ts)
+{
+	const struct vdso_data *vdata = get_vdso_data();
+	int ret = -1;
+
+	switch (clkid) {
+	case CLOCK_REALTIME_COARSE:
+		ret = do_realtime_coarse(ts, vdata);
+		break;
+	case CLOCK_MONOTONIC_COARSE:
+		ret = do_monotonic_coarse(ts, vdata);
+		break;
+	case CLOCK_REALTIME:
+		ret = do_realtime(ts, vdata);
+		break;
+	case CLOCK_MONOTONIC:
+		ret = do_monotonic(ts, vdata);
+		break;
+	default:
+		break;
+	}
+
+	if (ret)
+		ret = clock_gettime_fallback(clkid, ts);
+
+	return ret;
+}
+
+static notrace long gettimeofday_fallback(struct timeval *_tv,
+					  struct timezone *_tz)
+{
+	register struct timezone *tz asm("r1") = _tz;
+	register struct timeval *tv asm("r0") = _tv;
+	register long ret asm ("r0");
+	register long nr asm("r7") = __NR_compat_gettimeofday;
+
+	asm volatile(
+	"	svc #0\n"
+	: "=r" (ret)
+	: "r" (tv), "r" (tz), "r" (nr)
+	: "memory");
+
+	return ret;
+}
+
+notrace int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
+{
+	struct timespec ts;
+	const struct vdso_data *vdata = get_vdso_data();
+	int ret;
+
+	ret = do_realtime(&ts, vdata);
+	if (ret)
+		return gettimeofday_fallback(tv, tz);
+
+	if (tv) {
+		tv->tv_sec = ts.tv_sec;
+		tv->tv_usec = ts.tv_nsec / 1000;
+	}
+	if (tz) {
+		tz->tz_minuteswest = vdata->tz_minuteswest;
+		tz->tz_dsttime = vdata->tz_dsttime;
+	}
+
+	return ret;
+}
+
+/* Avoid unresolved references emitted by GCC */
+
+void __aeabi_unwind_cpp_pr0(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr1(void)
+{
+}
+
+void __aeabi_unwind_cpp_pr2(void)
+{
+}
-- 
2.8.2

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

* [PATCH 5/8] arm64: compat: 32-bit vDSO setup
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (3 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 4/8] arm64: compat: Add a 32-bit vDSO Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 6/8] arm64: elf: Set AT_SYSINFO_EHDR in compat processes Kevin Brodsky
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

If the compat vDSO is enabled, install it in compat processes. In this
case, the compat vDSO replaces the vector page.

aarch32_setup_vectors_page has also been renamed to the more generic
aarch32_setup_additional_pages to reflect both use cases.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/elf.h |  6 +++---
 arch/arm64/kernel/vdso.c     | 22 +++++++++++++++++++++-
 2 files changed, 24 insertions(+), 4 deletions(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index 24ed037f09fd..d811f81bdd11 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -183,10 +183,10 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
 #define COMPAT_ARCH_DLINFO
-extern int aarch32_setup_vectors_page(struct linux_binprm *bprm,
-				      int uses_interp);
+extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
+					  int uses_interp);
 #define compat_arch_setup_additional_pages \
-					aarch32_setup_vectors_page
+					aarch32_setup_additional_pages
 
 #endif /* CONFIG_COMPAT */
 
diff --git a/arch/arm64/kernel/vdso.c b/arch/arm64/kernel/vdso.c
index b9a1268c21c6..2b7f4dc44758 100644
--- a/arch/arm64/kernel/vdso.c
+++ b/arch/arm64/kernel/vdso.c
@@ -138,6 +138,25 @@ up_fail:
 }
 
 #ifdef CONFIG_COMPAT
+#ifdef CONFIG_VDSO32
+extern char vdso32_start, vdso32_end;
+
+static struct vdso_mappings vdso32_mappings;
+
+static int __init vdso32_init(void)
+{
+	return setup_vdso_mappings("vdso32", &vdso32_start, &vdso32_end,
+				   &vdso32_mappings);
+}
+arch_initcall(vdso32_init);
+
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
+{
+	return setup_vdso_pages(&vdso32_mappings);
+}
+
+#else /* CONFIG_VDSO32 */
+
 /*
  * Create and map the vectors page for AArch32 tasks.
  */
@@ -172,7 +191,7 @@ static int alloc_vectors_page(void)
 }
 arch_initcall(alloc_vectors_page);
 
-int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
+int aarch32_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 {
 	struct mm_struct *mm = current->mm;
 	unsigned long addr = AARCH32_VECTORS_BASE;
@@ -195,6 +214,7 @@ int aarch32_setup_vectors_page(struct linux_binprm *bprm, int uses_interp)
 
 	return PTR_ERR_OR_ZERO(ret);
 }
+#endif /* CONFIG_VDSO32 */
 #endif /* CONFIG_COMPAT */
 
 extern char vdso_start, vdso_end;
-- 
2.8.2

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

* [PATCH 6/8] arm64: elf: Set AT_SYSINFO_EHDR in compat processes
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (4 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 5/8] arm64: compat: 32-bit vDSO setup Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 7/8] arm64: compat: Use vDSO sigreturn trampolines if available Kevin Brodsky
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

If the compat vDSO is enabled, we need to set AT_SYSINFO_EHDR in the
auxiliary vector of compat processes to the address of the vDSO, so
that userspace (libc) can find it (just like the regular vDSO).

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/elf.h | 7 ++++++-
 1 file changed, 6 insertions(+), 1 deletion(-)

diff --git a/arch/arm64/include/asm/elf.h b/arch/arm64/include/asm/elf.h
index d811f81bdd11..c0e9156ebc75 100644
--- a/arch/arm64/include/asm/elf.h
+++ b/arch/arm64/include/asm/elf.h
@@ -140,11 +140,12 @@ typedef struct user_fpsimd_state elf_fpregset_t;
 
 #define SET_PERSONALITY(ex)		clear_thread_flag(TIF_32BIT);
 
-#define ARCH_DLINFO							\
+#define _SET_AUX_ENT_VDSO						\
 do {									\
 	NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
 		    (elf_addr_t)current->mm->context.vdso);		\
 } while (0)
+#define ARCH_DLINFO _SET_AUX_ENT_VDSO
 
 #define ARCH_HAS_SETUP_ADDITIONAL_PAGES
 struct linux_binprm;
@@ -182,7 +183,11 @@ typedef compat_elf_greg_t		compat_elf_gregset_t[COMPAT_ELF_NGREG];
 
 #define compat_start_thread		compat_start_thread
 #define COMPAT_SET_PERSONALITY(ex)	set_thread_flag(TIF_32BIT);
+#ifdef CONFIG_VDSO32
+#define COMPAT_ARCH_DLINFO		_SET_AUX_ENT_VDSO
+#else
 #define COMPAT_ARCH_DLINFO
+#endif
 extern int aarch32_setup_additional_pages(struct linux_binprm *bprm,
 					  int uses_interp);
 #define compat_arch_setup_additional_pages \
-- 
2.8.2

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

* [PATCH 7/8] arm64: compat: Use vDSO sigreturn trampolines if available
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (5 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 6/8] arm64: elf: Set AT_SYSINFO_EHDR in compat processes Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 13:53 ` [PATCH 8/8] arm64: Wire up and expose the new compat vDSO Kevin Brodsky
  2016-09-08 14:00 ` [PATCH 0/8] arm64: Add a " Kevin Brodsky
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

If the compat vDSO is enabled, it replaces the vector page. Therefore,
we use the sigreturn trampolines it provides instead of those in the
vector page.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/include/asm/vdso.h |  3 +++
 arch/arm64/kernel/signal32.c  | 15 +++++++++++++++
 2 files changed, 18 insertions(+)

diff --git a/arch/arm64/include/asm/vdso.h b/arch/arm64/include/asm/vdso.h
index 839ce0031bd5..f2a952338f1e 100644
--- a/arch/arm64/include/asm/vdso.h
+++ b/arch/arm64/include/asm/vdso.h
@@ -28,6 +28,9 @@
 #ifndef __ASSEMBLY__
 
 #include <generated/vdso-offsets.h>
+#ifdef CONFIG_VDSO32
+#include <generated/vdso32-offsets.h>
+#endif
 
 #define VDSO_SYMBOL(base, name)						   \
 ({									   \
diff --git a/arch/arm64/kernel/signal32.c b/arch/arm64/kernel/signal32.c
index 9de7d128e0e0..b72a4180a531 100644
--- a/arch/arm64/kernel/signal32.c
+++ b/arch/arm64/kernel/signal32.c
@@ -28,6 +28,7 @@
 #include <asm/signal32.h>
 #include <asm/uaccess.h>
 #include <asm/unistd.h>
+#include <asm/vdso.h>
 
 struct compat_vfp_sigframe {
 	compat_ulong_t	magic;
@@ -438,6 +439,19 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = ptr_to_compat(ka->sa.sa_restorer);
 	} else {
 		/* Set up sigreturn pointer */
+#ifdef CONFIG_VDSO32
+		void *vdso_page = current->mm->context.vdso;
+		void *trampoline =
+			(ka->sa.sa_flags & SA_SIGINFO
+			 ? (thumb
+			    ? VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_page, compat_rt_sigreturn_arm))
+			 : (thumb
+			    ? VDSO_SYMBOL(vdso_page, compat_sigreturn_thumb)
+			    : VDSO_SYMBOL(vdso_page, compat_sigreturn_arm)));
+
+		retcode = ptr_to_compat(trampoline) + thumb;
+#else
 		unsigned int idx = thumb << 1;
 
 		if (ka->sa.sa_flags & SA_SIGINFO)
@@ -446,6 +460,7 @@ static void compat_setup_return(struct pt_regs *regs, struct k_sigaction *ka,
 		retcode = AARCH32_VECTORS_BASE +
 			  AARCH32_KERN_SIGRET_CODE_OFFSET +
 			  (idx << 2) + thumb;
+#endif
 	}
 
 	regs->regs[0]	= usig;
-- 
2.8.2

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

* [PATCH 8/8] arm64: Wire up and expose the new compat vDSO
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (6 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 7/8] arm64: compat: Use vDSO sigreturn trampolines if available Kevin Brodsky
@ 2016-09-08 13:53 ` Kevin Brodsky
  2016-09-08 14:00 ` [PATCH 0/8] arm64: Add a " Kevin Brodsky
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 13:53 UTC (permalink / raw)
  To: linux-arm-kernel

Expose the new compat vDSO via the COMPAT_VDSO config option.

The option is not enabled by default for two reasons:

* The vDSO page replaces the vector page. The vDSO provides its own
  sigreturn trampolines, replacing those in the vector page, but the
  kuser helpers are gone. As a result enabling the compat vDSO will
  break userspace programs relying on the kuser helpers.

* We really need a 32-bit compiler this time, and we rely on the user
  to provide it themselves by setting CROSS_COMPILE_ARM32. Therefore
  enabling the option by default would make little sense, since the
  user must explicitly set an environment variable anyway.

CONFIG_COMPAT_VDSO is not directly used in the code, because we want
to ignore it (build as if it were not set) if the user didn't set
CROSS_COMPILE_ARM32 properly. If the variable has been set to a valid
prefix, CONFIG_VDSO32 will be set; this is the option that the code
and Makefiles will test.

Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
---
 arch/arm64/Kconfig         | 20 ++++++++++++++++++++
 arch/arm64/Makefile        | 20 ++++++++++++++++++--
 arch/arm64/kernel/Makefile |  9 ++++++---
 3 files changed, 44 insertions(+), 5 deletions(-)

diff --git a/arch/arm64/Kconfig b/arch/arm64/Kconfig
index 4f436220384f..02c1aa6ab90c 100644
--- a/arch/arm64/Kconfig
+++ b/arch/arm64/Kconfig
@@ -947,6 +947,26 @@ config SYSVIPC_COMPAT
 	def_bool y
 	depends on COMPAT && SYSVIPC
 
+config COMPAT_VDSO
+	bool "32-bit vDSO"
+	depends on COMPAT
+	default n
+	help
+	  Warning: this completely removes the compat vector page, including
+	  kuser helpers, which may break 32-bit processes.
+
+	  Warning: a 32-bit toolchain is necessary to build the vDSO. You
+	  must explicitly define which toolchain should be used by setting
+	  CROSS_COMPILE_ARM32 to the prefix of the 32-bit toolchain (same format
+	  as CROSS_COMPILE). If a 32-bit compiler cannot be found, a warning
+	  will be printed and the kernel will be built as if COMPAT_VDSO had not
+	  been set.
+
+	  Provide a vDSO to 32-bit processes. It includes the symbols provided
+	  by the vDSO from the 32-bit kernel, so that a 32-bit libc can use
+	  the compat vDSO without modification. It also provides sigreturn
+	  trampolines, and replaces the vector page.
+
 endmenu
 
 menu "Power management options"
diff --git a/arch/arm64/Makefile b/arch/arm64/Makefile
index 7bb702a0f1e2..992df1553374 100644
--- a/arch/arm64/Makefile
+++ b/arch/arm64/Makefile
@@ -30,10 +30,24 @@ $(warning LSE atomics not supported by binutils)
   endif
 endif
 
-KBUILD_CFLAGS	+= -mgeneral-regs-only $(lseinstr)
+ifeq ($(CONFIG_COMPAT_VDSO), y)
+  # Check that the user has provided a valid prefix for arm32 (we allow
+  # CROSS_COMPILE_ARM32 to be defined but empty, in case the system gcc should
+  # be used)
+  ifeq ($(shell [ -v CROSS_COMPILE_ARM32 ] && echo y),)
+    $(warning CROSS_COMPILE_ARM32 not defined, the compat vDSO will not be built)
+  else ifeq ($(shell which $(CROSS_COMPILE_ARM32)gcc 2> /dev/null),)
+    $(warning $(CROSS_COMPILE_ARM32)gcc not found, the compat vDSO will not be built)
+  else
+    export CONFIG_VDSO32 := y
+    vdso32 := -DCONFIG_VDSO32=1
+  endif
+endif
+
+KBUILD_CFLAGS	+= -mgeneral-regs-only $(lseinstr) $(vdso32)
 KBUILD_CFLAGS	+= -fno-asynchronous-unwind-tables
 KBUILD_CFLAGS	+= $(call cc-option, -mpc-relative-literal-loads)
-KBUILD_AFLAGS	+= $(lseinstr)
+KBUILD_AFLAGS	+= $(lseinstr) $(vdso32)
 
 ifeq ($(CONFIG_CPU_BIG_ENDIAN), y)
 KBUILD_CPPFLAGS	+= -mbig-endian
@@ -128,6 +142,8 @@ archclean:
 prepare: vdso_prepare
 vdso_prepare: prepare0
 	$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso include/generated/vdso-offsets.h
+	$(if $(CONFIG_VDSO32),$(Q)$(MAKE) $(build)=arch/arm64/kernel/vdso32 \
+					  include/generated/vdso32-offsets.h)
 
 define archhelp
   echo  '* Image.gz      - Compressed kernel image (arch/$(ARCH)/boot/Image.gz)'
diff --git a/arch/arm64/kernel/Makefile b/arch/arm64/kernel/Makefile
index bab85990691d..d26a1441d794 100644
--- a/arch/arm64/kernel/Makefile
+++ b/arch/arm64/kernel/Makefile
@@ -25,9 +25,11 @@ OBJCOPYFLAGS := --prefix-symbols=__efistub_
 $(obj)/%.stub.o: $(obj)/%.o FORCE
 	$(call if_changed,objcopy)
 
-arm64-obj-$(CONFIG_COMPAT)		+= sys32.o kuser32.o signal32.o 	\
-					   sys_compat.o entry32.o		\
-					   ../../arm/kernel/opcodes.o
+arm64-obj-$(CONFIG_COMPAT)		+= sys32.o signal32.o sys_compat.o	\
+					   entry32.o ../../arm/kernel/opcodes.o
+ifneq ($(CONFIG_VDSO32),y)
+arm64-obj-y				+= kuser32.o
+endif
 arm64-obj-$(CONFIG_FUNCTION_TRACER)	+= ftrace.o entry-ftrace.o
 arm64-obj-$(CONFIG_MODULES)		+= arm64ksyms.o module.o
 arm64-obj-$(CONFIG_ARM64_MODULE_PLTS)	+= module-plts.o
@@ -47,6 +49,7 @@ arm64-obj-$(CONFIG_PARAVIRT)		+= paravirt.o
 arm64-obj-$(CONFIG_RANDOMIZE_BASE)	+= kaslr.o
 
 obj-y					+= $(arm64-obj-y) vdso/
+obj-$(CONFIG_VDSO32)			+= vdso32/
 obj-m					+= $(arm64-obj-m)
 head-y					:= head.o
 extra-y					+= $(head-y) vmlinux.lds
-- 
2.8.2

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

* [PATCH 0/8] arm64: Add a compat vDSO
  2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
                   ` (7 preceding siblings ...)
  2016-09-08 13:53 ` [PATCH 8/8] arm64: Wire up and expose the new compat vDSO Kevin Brodsky
@ 2016-09-08 14:00 ` Kevin Brodsky
  8 siblings, 0 replies; 10+ messages in thread
From: Kevin Brodsky @ 2016-09-08 14:00 UTC (permalink / raw)
  To: linux-arm-kernel

Please ignore this whole series, I sent the wrong version... Sorry for the noise! 
I'll be sending the right version momentarily.

Kevin

On 08/09/16 14:53, Kevin Brodsky wrote:
> Hi,
>
> This series adds support for a compat (AArch32) vDSO, providing two
> userspace functionalities to compat processes:
>
> * Time "virtual" syscalls (gettimeofday and clock_gettime). The
>    implementation is an adaptation of the arm vDSO (vgettimeofday.c),
>    using the same the data page as the 64-bit vDSO.
>
> * sigreturn trampolines, following the example of the 64-bit vDSO
>    (sigreturn.S), but slightly more complicated because we provide A32
>    and T32 variants for both sigreturn and rt_sigreturn.
>
> The first point brings the performance improvement expected of a vDSO,
> by implementing syscalls directly in userspace. The second point allows
> us to get rid of the compat vector page, at the expense of the kuser
> helpers (this is one reason for not enabling the compat vDSO by
> default).
>
> Unfortunately, this time we cannot escape using a 32-bit toolchain. To
> build the compat VDSO, CONFIG_COMPAT_VDSO must be set *and*
> CROSS_COMPILE_ARM32 must be defined to the prefix of a 32-bit compiler.
> Failure to do so will not prevent building the kernel, but a warning
> will be printed and the compat vDSO will not be built.
>
>
> The last patch requires my Makefile fix [1] to apply. I pushed the
> series on top of this patch on pdsw-git:
>
>    git at pdsw-git.cambridge.arm.com:users/kevbro01/linux compat-vdso
>
> I have only tested the series with a 64-bit userspace (+ 32-bit glibc).
> Testing it with a 32-bit userspace would be very welcome.
>
> Thanks,
> Kevin
>
> [1]: "arm64: fix vdso-offsets.h dependency"
>       http://lists.infradead.org/pipermail/linux-arm-kernel/2016-April/422307.html
>
> Kevin Brodsky (8):
>    arm64: Refactor vDSO setup
>    arm64: compat: Add time-related syscall numbers
>    arm64: compat: Expose offset to registers in sigframes
>    arm64: compat: Add a 32-bit vDSO
>    arm64: compat: 32-bit vDSO setup
>    arm64: elf: Set AT_SYSINFO_EHDR in compat processes
>    arm64: compat: Use vDSO sigreturn trampolines if available
>    arm64: Wire up and expose the new compat vDSO
>
>   arch/arm64/Kconfig                       |  20 +++
>   arch/arm64/Makefile                      |  20 ++-
>   arch/arm64/include/asm/elf.h             |  13 +-
>   arch/arm64/include/asm/signal32.h        |  46 +++++
>   arch/arm64/include/asm/unistd.h          |   2 +
>   arch/arm64/include/asm/vdso.h            |   3 +
>   arch/arm64/kernel/Makefile               |   9 +-
>   arch/arm64/kernel/asm-offsets.c          |  13 ++
>   arch/arm64/kernel/signal32.c             |  61 ++-----
>   arch/arm64/kernel/vdso.c                 | 196 +++++++++++++--------
>   arch/arm64/kernel/vdso32/Makefile        | 120 +++++++++++++
>   arch/arm64/kernel/vdso32/sigreturn.S     |  82 +++++++++
>   arch/arm64/kernel/vdso32/vdso.S          |  32 ++++
>   arch/arm64/kernel/vdso32/vdso.lds.S      |  98 +++++++++++
>   arch/arm64/kernel/vdso32/vgettimeofday.c | 294 +++++++++++++++++++++++++++++++
>   15 files changed, 876 insertions(+), 133 deletions(-)
>   create mode 100644 arch/arm64/kernel/vdso32/Makefile
>   create mode 100644 arch/arm64/kernel/vdso32/sigreturn.S
>   create mode 100644 arch/arm64/kernel/vdso32/vdso.S
>   create mode 100644 arch/arm64/kernel/vdso32/vdso.lds.S
>   create mode 100644 arch/arm64/kernel/vdso32/vgettimeofday.c
>

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

end of thread, other threads:[~2016-09-08 14:00 UTC | newest]

Thread overview: 10+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-09-08 13:53 [PATCH 0/8] arm64: Add a compat vDSO Kevin Brodsky
2016-09-08 13:53 ` [PATCH 1/8] arm64: Refactor vDSO setup Kevin Brodsky
2016-09-08 13:53 ` [PATCH 2/8] arm64: compat: Add time-related syscall numbers Kevin Brodsky
2016-09-08 13:53 ` [PATCH 3/8] arm64: compat: Expose offset to registers in sigframes Kevin Brodsky
2016-09-08 13:53 ` [PATCH 4/8] arm64: compat: Add a 32-bit vDSO Kevin Brodsky
2016-09-08 13:53 ` [PATCH 5/8] arm64: compat: 32-bit vDSO setup Kevin Brodsky
2016-09-08 13:53 ` [PATCH 6/8] arm64: elf: Set AT_SYSINFO_EHDR in compat processes Kevin Brodsky
2016-09-08 13:53 ` [PATCH 7/8] arm64: compat: Use vDSO sigreturn trampolines if available Kevin Brodsky
2016-09-08 13:53 ` [PATCH 8/8] arm64: Wire up and expose the new compat vDSO Kevin Brodsky
2016-09-08 14:00 ` [PATCH 0/8] arm64: Add a " Kevin Brodsky

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.