mirror of
				https://github.com/torvalds/linux.git
				synced 2025-11-04 02:30:34 +02:00 
			
		
		
		
	MIPS: Initial implementation of a VDSO
Add an initial implementation of a proper (i.e. an ELF shared library)
VDSO. With this commit it does not export any symbols, it only replaces
the current signal return trampoline page. A later commit will add user
implementations of gettimeofday()/clock_gettime().
To support both new toolchains and old ones which don't generate ABI
flags section, we define its content manually and then use a tool
(genvdso) to patch up the section to have the correct name and type.
genvdso also extracts symbol offsets ({,rt_}sigreturn) needed by the
kernel, and generates a C file containing a "struct mips_vdso_image"
containing both the VDSO data and these offsets. This C file is
compiled into the kernel.
On 64-bit kernels we require a different VDSO for each supported ABI,
so we may build up to 3 different VDSOs. The VDSO to use is selected by
the mips_abi structure.
A kernel/user shared data page is created and mapped below the VDSO
image. This is currently empty, but will be used by the user time
function implementations which are added later.
[markos.chandras@imgtec.com:
- Add more comments
- Move abi detection in genvdso.h since it's the get_symbol function
that needs it.
- Add an R6 specific way to calculate the base address of VDSO in order
to avoid the branch instruction which affects performance.
- Do not patch .gnu.attributes since it's not needed for dynamic linking.
- Simplify Makefile a little bit.
- checkpatch fixes
- Restrict VDSO support for binutils < 2.25 for pre-R6
- Include atomic64.h for O32 variant on MIPS64]
Signed-off-by: Alex Smith <alex.smith@imgtec.com>
Signed-off-by: Markos Chandras <markos.chandras@imgtec.com>
Cc: Matthew Fortune <matthew.fortune@imgtec.com>
Cc: linux-mips@linux-mips.org
Patchwork: https://patchwork.linux-mips.org/patch/11337/
Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
			
			
This commit is contained in:
		
							parent
							
								
									22773aa9b9
								
							
						
					
					
						commit
						ebb5e78cc6
					
				
					 19 changed files with 1113 additions and 123 deletions
				
			
		| 
						 | 
					@ -17,6 +17,7 @@ obj- := $(platform-)
 | 
				
			||||||
obj-y += kernel/
 | 
					obj-y += kernel/
 | 
				
			||||||
obj-y += mm/
 | 
					obj-y += mm/
 | 
				
			||||||
obj-y += net/
 | 
					obj-y += net/
 | 
				
			||||||
 | 
					obj-y += vdso/
 | 
				
			||||||
 | 
					
 | 
				
			||||||
ifdef CONFIG_KVM
 | 
					ifdef CONFIG_KVM
 | 
				
			||||||
obj-y += kvm/
 | 
					obj-y += kvm/
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -11,19 +11,20 @@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <asm/signal.h>
 | 
					#include <asm/signal.h>
 | 
				
			||||||
#include <asm/siginfo.h>
 | 
					#include <asm/siginfo.h>
 | 
				
			||||||
 | 
					#include <asm/vdso.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mips_abi {
 | 
					struct mips_abi {
 | 
				
			||||||
	int (* const setup_frame)(void *sig_return, struct ksignal *ksig,
 | 
						int (* const setup_frame)(void *sig_return, struct ksignal *ksig,
 | 
				
			||||||
				  struct pt_regs *regs, sigset_t *set);
 | 
									  struct pt_regs *regs, sigset_t *set);
 | 
				
			||||||
	const unsigned long	signal_return_offset;
 | 
					 | 
				
			||||||
	int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig,
 | 
						int (* const setup_rt_frame)(void *sig_return, struct ksignal *ksig,
 | 
				
			||||||
				     struct pt_regs *regs, sigset_t *set);
 | 
									     struct pt_regs *regs, sigset_t *set);
 | 
				
			||||||
	const unsigned long	rt_signal_return_offset;
 | 
					 | 
				
			||||||
	const unsigned long	restart;
 | 
						const unsigned long	restart;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	unsigned	off_sc_fpregs;
 | 
						unsigned	off_sc_fpregs;
 | 
				
			||||||
	unsigned	off_sc_fpc_csr;
 | 
						unsigned	off_sc_fpc_csr;
 | 
				
			||||||
	unsigned	off_sc_used_math;
 | 
						unsigned	off_sc_used_math;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						struct mips_vdso_image *vdso;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* _ASM_ABI_H */
 | 
					#endif /* _ASM_ABI_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -8,6 +8,7 @@
 | 
				
			||||||
#ifndef _ASM_ELF_H
 | 
					#ifndef _ASM_ELF_H
 | 
				
			||||||
#define _ASM_ELF_H
 | 
					#define _ASM_ELF_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/auxvec.h>
 | 
				
			||||||
#include <linux/fs.h>
 | 
					#include <linux/fs.h>
 | 
				
			||||||
#include <uapi/linux/elf.h>
 | 
					#include <uapi/linux/elf.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -419,6 +420,12 @@ extern const char *__elf_platform;
 | 
				
			||||||
#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
 | 
					#define ELF_ET_DYN_BASE		(TASK_SIZE / 3 * 2)
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ARCH_DLINFO							\
 | 
				
			||||||
 | 
					do {									\
 | 
				
			||||||
 | 
						NEW_AUX_ENT(AT_SYSINFO_EHDR,					\
 | 
				
			||||||
 | 
							    (unsigned long)current->mm->context.vdso);		\
 | 
				
			||||||
 | 
					} while (0)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 | 
					#define ARCH_HAS_SETUP_ADDITIONAL_PAGES 1
 | 
				
			||||||
struct linux_binprm;
 | 
					struct linux_binprm;
 | 
				
			||||||
extern int arch_setup_additional_pages(struct linux_binprm *bprm,
 | 
					extern int arch_setup_additional_pages(struct linux_binprm *bprm,
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -36,12 +36,6 @@ extern unsigned int vced_count, vcei_count;
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
 | 
					#define HAVE_ARCH_PICK_MMAP_LAYOUT 1
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					 | 
				
			||||||
 * A special page (the vdso) is mapped into all processes at the very
 | 
					 | 
				
			||||||
 * top of the virtual memory space.
 | 
					 | 
				
			||||||
 */
 | 
					 | 
				
			||||||
#define SPECIAL_PAGES_SIZE PAGE_SIZE
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
#ifdef CONFIG_32BIT
 | 
					#ifdef CONFIG_32BIT
 | 
				
			||||||
#ifdef CONFIG_KVM_GUEST
 | 
					#ifdef CONFIG_KVM_GUEST
 | 
				
			||||||
/* User space process size is limited to 1GB in KVM Guest Mode */
 | 
					/* User space process size is limited to 1GB in KVM Guest Mode */
 | 
				
			||||||
| 
						 | 
					@ -80,7 +74,7 @@ extern unsigned int vced_count, vcei_count;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#define STACK_TOP	((TASK_SIZE & PAGE_MASK) - SPECIAL_PAGES_SIZE)
 | 
					#define STACK_TOP	(TASK_SIZE & PAGE_MASK)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This decides where the kernel will search for a free chunk of vm
 | 
					 * This decides where the kernel will search for a free chunk of vm
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,29 +1,70 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This file is subject to the terms and conditions of the GNU General Public
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 * License.  See the file "COPYING" in the main directory of this archive
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 * for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (C) 2009 Cavium Networks
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifndef __ASM_VDSO_H
 | 
					#ifndef __ASM_VDSO_H
 | 
				
			||||||
#define __ASM_VDSO_H
 | 
					#define __ASM_VDSO_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include <linux/types.h>
 | 
					#include <linux/mm_types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * struct mips_vdso_image - Details of a VDSO image.
 | 
				
			||||||
 | 
					 * @data: Pointer to VDSO image data (page-aligned).
 | 
				
			||||||
 | 
					 * @size: Size of the VDSO image data (page-aligned).
 | 
				
			||||||
 | 
					 * @off_sigreturn: Offset of the sigreturn() trampoline.
 | 
				
			||||||
 | 
					 * @off_rt_sigreturn: Offset of the rt_sigreturn() trampoline.
 | 
				
			||||||
 | 
					 * @mapping: Special mapping structure.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This structure contains details of a VDSO image, including the image data
 | 
				
			||||||
 | 
					 * and offsets of certain symbols required by the kernel. It is generated as
 | 
				
			||||||
 | 
					 * part of the VDSO build process, aside from the mapping page array, which is
 | 
				
			||||||
 | 
					 * populated at runtime.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					struct mips_vdso_image {
 | 
				
			||||||
 | 
						void *data;
 | 
				
			||||||
 | 
						unsigned long size;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#ifdef CONFIG_32BIT
 | 
						unsigned long off_sigreturn;
 | 
				
			||||||
struct mips_vdso {
 | 
						unsigned long off_rt_sigreturn;
 | 
				
			||||||
	u32 signal_trampoline[2];
 | 
					
 | 
				
			||||||
	u32 rt_signal_trampoline[2];
 | 
						struct vm_special_mapping mapping;
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#else  /* !CONFIG_32BIT */
 | 
					
 | 
				
			||||||
struct mips_vdso {
 | 
					/*
 | 
				
			||||||
	u32 o32_signal_trampoline[2];
 | 
					 * The following structures are auto-generated as part of the build for each
 | 
				
			||||||
	u32 o32_rt_signal_trampoline[2];
 | 
					 * ABI by genvdso, see arch/mips/vdso/Makefile.
 | 
				
			||||||
	u32 rt_signal_trampoline[2];
 | 
					 */
 | 
				
			||||||
	u32 n32_rt_signal_trampoline[2];
 | 
					
 | 
				
			||||||
 | 
					extern struct mips_vdso_image vdso_image;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MIPS32_O32
 | 
				
			||||||
 | 
					extern struct mips_vdso_image vdso_image_o32;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifdef CONFIG_MIPS32_N32
 | 
				
			||||||
 | 
					extern struct mips_vdso_image vdso_image_n32;
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/**
 | 
				
			||||||
 | 
					 * union mips_vdso_data - Data provided by the kernel for the VDSO.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * This structure contains data needed by functions within the VDSO. It is
 | 
				
			||||||
 | 
					 * populated by the kernel and mapped read-only into user memory.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * Note: Care should be taken when modifying as the layout must remain the same
 | 
				
			||||||
 | 
					 * for both 64- and 32-bit (for 32-bit userland on 64-bit kernel).
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					union mips_vdso_data {
 | 
				
			||||||
 | 
						struct {
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						u8 page[PAGE_SIZE];
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
#endif /* CONFIG_32BIT */
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#endif /* __ASM_VDSO_H */
 | 
					#endif /* __ASM_VDSO_H */
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,9 +1,9 @@
 | 
				
			||||||
# UAPI Header export list
 | 
					# UAPI Header export list
 | 
				
			||||||
include include/uapi/asm-generic/Kbuild.asm
 | 
					include include/uapi/asm-generic/Kbuild.asm
 | 
				
			||||||
 | 
					
 | 
				
			||||||
generic-y += auxvec.h
 | 
					 | 
				
			||||||
generic-y += ipcbuf.h
 | 
					generic-y += ipcbuf.h
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					header-y += auxvec.h
 | 
				
			||||||
header-y += bitfield.h
 | 
					header-y += bitfield.h
 | 
				
			||||||
header-y += bitsperlong.h
 | 
					header-y += bitsperlong.h
 | 
				
			||||||
header-y += break.h
 | 
					header-y += break.h
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										17
									
								
								arch/mips/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										17
									
								
								arch/mips/include/uapi/asm/auxvec.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,17 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASM_AUXVEC_H
 | 
				
			||||||
 | 
					#define __ASM_AUXVEC_H
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Location of VDSO image. */
 | 
				
			||||||
 | 
					#define AT_SYSINFO_EHDR		33
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __ASM_AUXVEC_H */
 | 
				
			||||||
| 
						 | 
					@ -36,7 +36,6 @@
 | 
				
			||||||
#include <asm/ucontext.h>
 | 
					#include <asm/ucontext.h>
 | 
				
			||||||
#include <asm/cpu-features.h>
 | 
					#include <asm/cpu-features.h>
 | 
				
			||||||
#include <asm/war.h>
 | 
					#include <asm/war.h>
 | 
				
			||||||
#include <asm/vdso.h>
 | 
					 | 
				
			||||||
#include <asm/dsp.h>
 | 
					#include <asm/dsp.h>
 | 
				
			||||||
#include <asm/inst.h>
 | 
					#include <asm/inst.h>
 | 
				
			||||||
#include <asm/msa.h>
 | 
					#include <asm/msa.h>
 | 
				
			||||||
| 
						 | 
					@ -752,16 +751,15 @@ static int setup_rt_frame(void *sig_return, struct ksignal *ksig,
 | 
				
			||||||
struct mips_abi mips_abi = {
 | 
					struct mips_abi mips_abi = {
 | 
				
			||||||
#ifdef CONFIG_TRAD_SIGNALS
 | 
					#ifdef CONFIG_TRAD_SIGNALS
 | 
				
			||||||
	.setup_frame	= setup_frame,
 | 
						.setup_frame	= setup_frame,
 | 
				
			||||||
	.signal_return_offset = offsetof(struct mips_vdso, signal_trampoline),
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
	.setup_rt_frame = setup_rt_frame,
 | 
						.setup_rt_frame = setup_rt_frame,
 | 
				
			||||||
	.rt_signal_return_offset =
 | 
					 | 
				
			||||||
		offsetof(struct mips_vdso, rt_signal_trampoline),
 | 
					 | 
				
			||||||
	.restart	= __NR_restart_syscall,
 | 
						.restart	= __NR_restart_syscall,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
 | 
						.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
 | 
				
			||||||
	.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
 | 
						.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
 | 
				
			||||||
	.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
 | 
						.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.vdso		= &vdso_image,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 | 
					static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 | 
				
			||||||
| 
						 | 
					@ -801,11 +799,11 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)
 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	if (sig_uses_siginfo(&ksig->ka))
 | 
						if (sig_uses_siginfo(&ksig->ka))
 | 
				
			||||||
		ret = abi->setup_rt_frame(vdso + abi->rt_signal_return_offset,
 | 
							ret = abi->setup_rt_frame(vdso + abi->vdso->off_rt_sigreturn,
 | 
				
			||||||
					  ksig, regs, oldset);
 | 
										  ksig, regs, oldset);
 | 
				
			||||||
	else
 | 
						else
 | 
				
			||||||
		ret = abi->setup_frame(vdso + abi->signal_return_offset, ksig,
 | 
							ret = abi->setup_frame(vdso + abi->vdso->off_sigreturn,
 | 
				
			||||||
				       regs, oldset);
 | 
									       ksig, regs, oldset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	signal_setup_done(ret, ksig, 0);
 | 
						signal_setup_done(ret, ksig, 0);
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -31,7 +31,6 @@
 | 
				
			||||||
#include <asm/ucontext.h>
 | 
					#include <asm/ucontext.h>
 | 
				
			||||||
#include <asm/fpu.h>
 | 
					#include <asm/fpu.h>
 | 
				
			||||||
#include <asm/war.h>
 | 
					#include <asm/war.h>
 | 
				
			||||||
#include <asm/vdso.h>
 | 
					 | 
				
			||||||
#include <asm/dsp.h>
 | 
					#include <asm/dsp.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "signal-common.h"
 | 
					#include "signal-common.h"
 | 
				
			||||||
| 
						 | 
					@ -406,14 +405,12 @@ static int setup_rt_frame_32(void *sig_return, struct ksignal *ksig,
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
struct mips_abi mips_abi_32 = {
 | 
					struct mips_abi mips_abi_32 = {
 | 
				
			||||||
	.setup_frame	= setup_frame_32,
 | 
						.setup_frame	= setup_frame_32,
 | 
				
			||||||
	.signal_return_offset =
 | 
					 | 
				
			||||||
		offsetof(struct mips_vdso, o32_signal_trampoline),
 | 
					 | 
				
			||||||
	.setup_rt_frame = setup_rt_frame_32,
 | 
						.setup_rt_frame = setup_rt_frame_32,
 | 
				
			||||||
	.rt_signal_return_offset =
 | 
					 | 
				
			||||||
		offsetof(struct mips_vdso, o32_rt_signal_trampoline),
 | 
					 | 
				
			||||||
	.restart	= __NR_O32_restart_syscall,
 | 
						.restart	= __NR_O32_restart_syscall,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
 | 
						.off_sc_fpregs = offsetof(struct sigcontext32, sc_fpregs),
 | 
				
			||||||
	.off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
 | 
						.off_sc_fpc_csr = offsetof(struct sigcontext32, sc_fpc_csr),
 | 
				
			||||||
	.off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
 | 
						.off_sc_used_math = offsetof(struct sigcontext32, sc_used_math),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.vdso		= &vdso_image_o32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -38,7 +38,6 @@
 | 
				
			||||||
#include <asm/fpu.h>
 | 
					#include <asm/fpu.h>
 | 
				
			||||||
#include <asm/cpu-features.h>
 | 
					#include <asm/cpu-features.h>
 | 
				
			||||||
#include <asm/war.h>
 | 
					#include <asm/war.h>
 | 
				
			||||||
#include <asm/vdso.h>
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
#include "signal-common.h"
 | 
					#include "signal-common.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
| 
						 | 
					@ -151,11 +150,11 @@ static int setup_rt_frame_n32(void *sig_return, struct ksignal *ksig,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
struct mips_abi mips_abi_n32 = {
 | 
					struct mips_abi mips_abi_n32 = {
 | 
				
			||||||
	.setup_rt_frame = setup_rt_frame_n32,
 | 
						.setup_rt_frame = setup_rt_frame_n32,
 | 
				
			||||||
	.rt_signal_return_offset =
 | 
					 | 
				
			||||||
		offsetof(struct mips_vdso, n32_rt_signal_trampoline),
 | 
					 | 
				
			||||||
	.restart	= __NR_N32_restart_syscall,
 | 
						.restart	= __NR_N32_restart_syscall,
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
 | 
						.off_sc_fpregs = offsetof(struct sigcontext, sc_fpregs),
 | 
				
			||||||
	.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
 | 
						.off_sc_fpc_csr = offsetof(struct sigcontext, sc_fpc_csr),
 | 
				
			||||||
	.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
 | 
						.off_sc_used_math = offsetof(struct sigcontext, sc_used_math),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.vdso		= &vdso_image_n32,
 | 
				
			||||||
};
 | 
					};
 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
| 
						 | 
					@ -1,122 +1,116 @@
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * This file is subject to the terms and conditions of the GNU General Public
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 * License.  See the file "COPYING" in the main directory of this archive
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 * for more details.
 | 
					 | 
				
			||||||
 *
 | 
					 *
 | 
				
			||||||
 * Copyright (C) 2009, 2010 Cavium Networks, Inc.
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					 | 
				
			||||||
#include <linux/kernel.h>
 | 
					 | 
				
			||||||
#include <linux/err.h>
 | 
					 | 
				
			||||||
#include <linux/sched.h>
 | 
					 | 
				
			||||||
#include <linux/mm.h>
 | 
					 | 
				
			||||||
#include <linux/init.h>
 | 
					 | 
				
			||||||
#include <linux/binfmts.h>
 | 
					#include <linux/binfmts.h>
 | 
				
			||||||
#include <linux/elf.h>
 | 
					#include <linux/elf.h>
 | 
				
			||||||
#include <linux/vmalloc.h>
 | 
					#include <linux/err.h>
 | 
				
			||||||
#include <linux/unistd.h>
 | 
					#include <linux/init.h>
 | 
				
			||||||
#include <linux/random.h>
 | 
					#include <linux/mm.h>
 | 
				
			||||||
 | 
					#include <linux/sched.h>
 | 
				
			||||||
 | 
					#include <linux/slab.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/abi.h>
 | 
				
			||||||
#include <asm/vdso.h>
 | 
					#include <asm/vdso.h>
 | 
				
			||||||
#include <asm/uasm.h>
 | 
					
 | 
				
			||||||
#include <asm/processor.h>
 | 
					/* Kernel-provided data used by the VDSO. */
 | 
				
			||||||
 | 
					static union mips_vdso_data vdso_data __page_aligned_data;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
/*
 | 
					/*
 | 
				
			||||||
 * Including <asm/unistd.h> would give use the 64-bit syscall numbers ...
 | 
					 * Mapping for the VDSO data pages. The real pages are mapped manually, as
 | 
				
			||||||
 | 
					 * what we map and where within the area they are mapped is determined at
 | 
				
			||||||
 | 
					 * runtime.
 | 
				
			||||||
 */
 | 
					 */
 | 
				
			||||||
#define __NR_O32_sigreturn		4119
 | 
					static struct page *no_pages[] = { NULL };
 | 
				
			||||||
#define __NR_O32_rt_sigreturn		4193
 | 
					static struct vm_special_mapping vdso_vvar_mapping = {
 | 
				
			||||||
#define __NR_N32_rt_sigreturn		6211
 | 
						.name = "[vvar]",
 | 
				
			||||||
 | 
						.pages = no_pages,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static struct page *vdso_page;
 | 
					static void __init init_vdso_image(struct mips_vdso_image *image)
 | 
				
			||||||
 | 
					 | 
				
			||||||
static void __init install_trampoline(u32 *tramp, unsigned int sigreturn)
 | 
					 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	uasm_i_addiu(&tramp, 2, 0, sigreturn);	/* li v0, sigreturn */
 | 
						unsigned long num_pages, i;
 | 
				
			||||||
	uasm_i_syscall(&tramp, 0);
 | 
					
 | 
				
			||||||
 | 
						BUG_ON(!PAGE_ALIGNED(image->data));
 | 
				
			||||||
 | 
						BUG_ON(!PAGE_ALIGNED(image->size));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						num_pages = image->size / PAGE_SIZE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < num_pages; i++) {
 | 
				
			||||||
 | 
							image->mapping.pages[i] =
 | 
				
			||||||
 | 
								virt_to_page(image->data + (i * PAGE_SIZE));
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static int __init init_vdso(void)
 | 
					static int __init init_vdso(void)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	struct mips_vdso *vdso;
 | 
						init_vdso_image(&vdso_image);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vdso_page = alloc_page(GFP_KERNEL);
 | 
					#ifdef CONFIG_MIPS32_O32
 | 
				
			||||||
	if (!vdso_page)
 | 
						init_vdso_image(&vdso_image_o32);
 | 
				
			||||||
		panic("Cannot allocate vdso");
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	vdso = vmap(&vdso_page, 1, 0, PAGE_KERNEL);
 | 
					 | 
				
			||||||
	if (!vdso)
 | 
					 | 
				
			||||||
		panic("Cannot map vdso");
 | 
					 | 
				
			||||||
	clear_page(vdso);
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	install_trampoline(vdso->rt_signal_trampoline, __NR_rt_sigreturn);
 | 
					 | 
				
			||||||
#ifdef CONFIG_32BIT
 | 
					 | 
				
			||||||
	install_trampoline(vdso->signal_trampoline, __NR_sigreturn);
 | 
					 | 
				
			||||||
#else
 | 
					 | 
				
			||||||
	install_trampoline(vdso->n32_rt_signal_trampoline,
 | 
					 | 
				
			||||||
			   __NR_N32_rt_sigreturn);
 | 
					 | 
				
			||||||
	install_trampoline(vdso->o32_signal_trampoline, __NR_O32_sigreturn);
 | 
					 | 
				
			||||||
	install_trampoline(vdso->o32_rt_signal_trampoline,
 | 
					 | 
				
			||||||
			   __NR_O32_rt_sigreturn);
 | 
					 | 
				
			||||||
#endif
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	vunmap(vdso);
 | 
					#ifdef CONFIG_MIPS32_N32
 | 
				
			||||||
 | 
						init_vdso_image(&vdso_image_n32);
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	return 0;
 | 
						return 0;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
subsys_initcall(init_vdso);
 | 
					subsys_initcall(init_vdso);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
static unsigned long vdso_addr(unsigned long start)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	unsigned long offset = 0UL;
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	if (current->flags & PF_RANDOMIZE) {
 | 
					 | 
				
			||||||
		offset = get_random_int();
 | 
					 | 
				
			||||||
		offset <<= PAGE_SHIFT;
 | 
					 | 
				
			||||||
		if (TASK_IS_32BIT_ADDR)
 | 
					 | 
				
			||||||
			offset &= 0xfffffful;
 | 
					 | 
				
			||||||
		else
 | 
					 | 
				
			||||||
			offset &= 0xffffffful;
 | 
					 | 
				
			||||||
	}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
	return STACK_TOP + offset;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
 | 
					 | 
				
			||||||
int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 | 
					int arch_setup_additional_pages(struct linux_binprm *bprm, int uses_interp)
 | 
				
			||||||
{
 | 
					{
 | 
				
			||||||
	int ret;
 | 
						struct mips_vdso_image *image = current->thread.abi->vdso;
 | 
				
			||||||
	unsigned long addr;
 | 
					 | 
				
			||||||
	struct mm_struct *mm = current->mm;
 | 
						struct mm_struct *mm = current->mm;
 | 
				
			||||||
 | 
						unsigned long base, vdso_addr;
 | 
				
			||||||
 | 
						struct vm_area_struct *vma;
 | 
				
			||||||
 | 
						int ret;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	down_write(&mm->mmap_sem);
 | 
						down_write(&mm->mmap_sem);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	addr = vdso_addr(mm->start_stack);
 | 
						base = get_unmapped_area(NULL, 0, PAGE_SIZE + image->size, 0, 0);
 | 
				
			||||||
 | 
						if (IS_ERR_VALUE(base)) {
 | 
				
			||||||
	addr = get_unmapped_area(NULL, addr, PAGE_SIZE, 0, 0);
 | 
							ret = base;
 | 
				
			||||||
	if (IS_ERR_VALUE(addr)) {
 | 
							goto out;
 | 
				
			||||||
		ret = addr;
 | 
					 | 
				
			||||||
		goto up_fail;
 | 
					 | 
				
			||||||
	}
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	ret = install_special_mapping(mm, addr, PAGE_SIZE,
 | 
						vdso_addr = base + PAGE_SIZE;
 | 
				
			||||||
				      VM_READ|VM_EXEC|
 | 
					 | 
				
			||||||
				      VM_MAYREAD|VM_MAYWRITE|VM_MAYEXEC,
 | 
					 | 
				
			||||||
				      &vdso_page);
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vma = _install_special_mapping(mm, base, PAGE_SIZE,
 | 
				
			||||||
 | 
									       VM_READ | VM_MAYREAD,
 | 
				
			||||||
 | 
									       &vdso_vvar_mapping);
 | 
				
			||||||
 | 
						if (IS_ERR(vma)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(vma);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Map data page. */
 | 
				
			||||||
 | 
						ret = remap_pfn_range(vma, base,
 | 
				
			||||||
 | 
								      virt_to_phys(&vdso_data) >> PAGE_SHIFT,
 | 
				
			||||||
 | 
								      PAGE_SIZE, PAGE_READONLY);
 | 
				
			||||||
	if (ret)
 | 
						if (ret)
 | 
				
			||||||
		goto up_fail;
 | 
							goto out;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
	mm->context.vdso = (void *)addr;
 | 
						/* Map VDSO image. */
 | 
				
			||||||
 | 
						vma = _install_special_mapping(mm, vdso_addr, image->size,
 | 
				
			||||||
 | 
									       VM_READ | VM_EXEC |
 | 
				
			||||||
 | 
									       VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC,
 | 
				
			||||||
 | 
									       &image->mapping);
 | 
				
			||||||
 | 
						if (IS_ERR(vma)) {
 | 
				
			||||||
 | 
							ret = PTR_ERR(vma);
 | 
				
			||||||
 | 
							goto out;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
up_fail:
 | 
						mm->context.vdso = (void *)vdso_addr;
 | 
				
			||||||
 | 
						ret = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					out:
 | 
				
			||||||
	up_write(&mm->mmap_sem);
 | 
						up_write(&mm->mmap_sem);
 | 
				
			||||||
	return ret;
 | 
						return ret;
 | 
				
			||||||
}
 | 
					}
 | 
				
			||||||
 | 
					 | 
				
			||||||
const char *arch_vma_name(struct vm_area_struct *vma)
 | 
					 | 
				
			||||||
{
 | 
					 | 
				
			||||||
	if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso)
 | 
					 | 
				
			||||||
		return "[vdso]";
 | 
					 | 
				
			||||||
	return NULL;
 | 
					 | 
				
			||||||
}
 | 
					 | 
				
			||||||
| 
						 | 
					
 | 
				
			||||||
							
								
								
									
										4
									
								
								arch/mips/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								arch/mips/vdso/.gitignore
									
									
									
									
										vendored
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,4 @@
 | 
				
			||||||
 | 
					*.so*
 | 
				
			||||||
 | 
					vdso-*image.c
 | 
				
			||||||
 | 
					genvdso
 | 
				
			||||||
 | 
					vdso*.lds
 | 
				
			||||||
							
								
								
									
										160
									
								
								arch/mips/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										160
									
								
								arch/mips/vdso/Makefile
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,160 @@
 | 
				
			||||||
 | 
					# Objects to go into the VDSO.
 | 
				
			||||||
 | 
					obj-vdso-y := elf.o gettimeofday.o sigreturn.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Common compiler flags between ABIs.
 | 
				
			||||||
 | 
					ccflags-vdso := \
 | 
				
			||||||
 | 
						$(filter -I%,$(KBUILD_CFLAGS)) \
 | 
				
			||||||
 | 
						$(filter -E%,$(KBUILD_CFLAGS)) \
 | 
				
			||||||
 | 
						$(filter -march=%,$(KBUILD_CFLAGS))
 | 
				
			||||||
 | 
					cflags-vdso := $(ccflags-vdso) \
 | 
				
			||||||
 | 
						$(filter -W%,$(filter-out -Wa$(comma)%,$(KBUILD_CFLAGS))) \
 | 
				
			||||||
 | 
						-O2 -g -fPIC -fno-common -fno-builtin -G 0 -DDISABLE_BRANCH_PROFILING \
 | 
				
			||||||
 | 
						$(call cc-option, -fno-stack-protector)
 | 
				
			||||||
 | 
					aflags-vdso := $(ccflags-vdso) \
 | 
				
			||||||
 | 
						$(filter -I%,$(KBUILD_CFLAGS)) \
 | 
				
			||||||
 | 
						$(filter -E%,$(KBUILD_CFLAGS)) \
 | 
				
			||||||
 | 
						-D__ASSEMBLY__ -Wa,-gdwarf-2
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# For the pre-R6 code in arch/mips/vdso/vdso.h for locating
 | 
				
			||||||
 | 
					# the base address of VDSO, the linker will emit a R_MIPS_PC32
 | 
				
			||||||
 | 
					# relocation in binutils > 2.25 but it will fail with older versions
 | 
				
			||||||
 | 
					# because that relocation is not supported for that symbol. As a result
 | 
				
			||||||
 | 
					# of which we are forced to disable the VDSO symbols when building
 | 
				
			||||||
 | 
					# with < 2.25 binutils on pre-R6 kernels. For more references on why we
 | 
				
			||||||
 | 
					# can't use other methods to get the base address of VDSO please refer to
 | 
				
			||||||
 | 
					# the comments on that file.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					ifndef CONFIG_CPU_MIPSR6
 | 
				
			||||||
 | 
					  ifeq ($(call ld-ifversion, -gt, 22400000, y),)
 | 
				
			||||||
 | 
					    $(warning MIPS VDSO requires binutils > 2.24)
 | 
				
			||||||
 | 
					    obj-vdso-y := $(filter-out gettimeofday.o, $(obj-vdso-y))
 | 
				
			||||||
 | 
					    ccflags-vdso += -DDISABLE_MIPS_VDSO
 | 
				
			||||||
 | 
					  endif
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# VDSO linker flags.
 | 
				
			||||||
 | 
					VDSO_LDFLAGS := \
 | 
				
			||||||
 | 
						-Wl,-Bsymbolic -Wl,--no-undefined -Wl,-soname=linux-vdso.so.1 \
 | 
				
			||||||
 | 
						-nostdlib -shared \
 | 
				
			||||||
 | 
						$(call cc-ldoption, -Wl$(comma)--hash-style=sysv) \
 | 
				
			||||||
 | 
						$(call cc-ldoption, -Wl$(comma)--build-id)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					GCOV_PROFILE := n
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Shared build commands.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					quiet_cmd_vdsold = VDSO    $@
 | 
				
			||||||
 | 
					      cmd_vdsold = $(CC) $(c_flags) $(VDSO_LDFLAGS) \
 | 
				
			||||||
 | 
					                   -Wl,-T $(filter %.lds,$^) $(filter %.o,$^) -o $@
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					hostprogs-y := genvdso
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					quiet_cmd_genvdso = GENVDSO $@
 | 
				
			||||||
 | 
					define cmd_genvdso
 | 
				
			||||||
 | 
						cp $< $(<:%.dbg=%) && \
 | 
				
			||||||
 | 
						$(OBJCOPY) -S $< $(<:%.dbg=%) && \
 | 
				
			||||||
 | 
						$(obj)/genvdso $< $(<:%.dbg=%) $@ $(VDSO_NAME)
 | 
				
			||||||
 | 
					endef
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Build native VDSO.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					native-abi := $(filter -mabi=%,$(KBUILD_CFLAGS))
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					targets += $(obj-vdso-y)
 | 
				
			||||||
 | 
					targets += vdso.lds vdso.so.dbg vdso.so vdso-image.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-vdso := $(obj-vdso-y:%.o=$(obj)/%.o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj-vdso): KBUILD_CFLAGS := $(cflags-vdso) $(native-abi)
 | 
				
			||||||
 | 
					$(obj-vdso): KBUILD_AFLAGS := $(aflags-vdso) $(native-abi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso.lds: KBUILD_CPPFLAGS := $(native-abi)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso.so.dbg: $(obj)/vdso.lds $(obj-vdso) FORCE
 | 
				
			||||||
 | 
						$(call if_changed,vdsold)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-image.c: $(obj)/vdso.so.dbg $(obj)/genvdso FORCE
 | 
				
			||||||
 | 
						$(call if_changed,genvdso)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-y += vdso-image.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Build O32 VDSO.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# Define these outside the ifdef to ensure they are picked up by clean.
 | 
				
			||||||
 | 
					targets += $(obj-vdso-y:%.o=%-o32.o)
 | 
				
			||||||
 | 
					targets += vdso-o32.lds vdso-o32.so.dbg vdso-o32.so vdso-o32-image.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifdef CONFIG_MIPS32_O32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-vdso-o32 := $(obj-vdso-y:%.o=$(obj)/%-o32.o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj-vdso-o32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=32
 | 
				
			||||||
 | 
					$(obj-vdso-o32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/%-o32.o: $(src)/%.S FORCE
 | 
				
			||||||
 | 
						$(call if_changed_dep,as_o_S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/%-o32.o: $(src)/%.c FORCE
 | 
				
			||||||
 | 
						$(call cmd,force_checksrc)
 | 
				
			||||||
 | 
						$(call if_changed_rule,cc_o_c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-o32.lds: KBUILD_CPPFLAGS := -mabi=32
 | 
				
			||||||
 | 
					$(obj)/vdso-o32.lds: $(src)/vdso.lds.S FORCE
 | 
				
			||||||
 | 
						$(call if_changed_dep,cpp_lds_S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-o32.so.dbg: $(obj)/vdso-o32.lds $(obj-vdso-o32) FORCE
 | 
				
			||||||
 | 
						$(call if_changed,vdsold)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-o32-image.c: VDSO_NAME := o32
 | 
				
			||||||
 | 
					$(obj)/vdso-o32-image.c: $(obj)/vdso-o32.so.dbg $(obj)/genvdso FORCE
 | 
				
			||||||
 | 
						$(call if_changed,genvdso)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-y += vdso-o32-image.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					# Build N32 VDSO.
 | 
				
			||||||
 | 
					#
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					targets += $(obj-vdso-y:%.o=%-n32.o)
 | 
				
			||||||
 | 
					targets += vdso-n32.lds vdso-n32.so.dbg vdso-n32.so vdso-n32-image.c
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ifdef CONFIG_MIPS32_N32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-vdso-n32 := $(obj-vdso-y:%.o=$(obj)/%-n32.o)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj-vdso-n32): KBUILD_CFLAGS := $(cflags-vdso) -mabi=n32
 | 
				
			||||||
 | 
					$(obj-vdso-n32): KBUILD_AFLAGS := $(aflags-vdso) -mabi=n32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/%-n32.o: $(src)/%.S FORCE
 | 
				
			||||||
 | 
						$(call if_changed_dep,as_o_S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/%-n32.o: $(src)/%.c FORCE
 | 
				
			||||||
 | 
						$(call cmd,force_checksrc)
 | 
				
			||||||
 | 
						$(call if_changed_rule,cc_o_c)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-n32.lds: KBUILD_CPPFLAGS := -mabi=n32
 | 
				
			||||||
 | 
					$(obj)/vdso-n32.lds: $(src)/vdso.lds.S FORCE
 | 
				
			||||||
 | 
						$(call if_changed_dep,cpp_lds_S)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-n32.so.dbg: $(obj)/vdso-n32.lds $(obj-vdso-n32) FORCE
 | 
				
			||||||
 | 
						$(call if_changed,vdsold)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					$(obj)/vdso-n32-image.c: VDSO_NAME := n32
 | 
				
			||||||
 | 
					$(obj)/vdso-n32-image.c: $(obj)/vdso-n32.so.dbg $(obj)/genvdso FORCE
 | 
				
			||||||
 | 
						$(call if_changed,genvdso)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					obj-y += vdso-n32-image.o
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					# FIXME: Need install rule for debug.
 | 
				
			||||||
 | 
					# Needs to deal with dependency for generation of dbg by cmd_genvdso...
 | 
				
			||||||
							
								
								
									
										68
									
								
								arch/mips/vdso/elf.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										68
									
								
								arch/mips/vdso/elf.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,68 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vdso.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <linux/elfnote.h>
 | 
				
			||||||
 | 
					#include <linux/version.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					ELFNOTE_START(Linux, 0, "a")
 | 
				
			||||||
 | 
						.long LINUX_VERSION_CODE
 | 
				
			||||||
 | 
					ELFNOTE_END
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * The .MIPS.abiflags section must be defined with the FP ABI flags set
 | 
				
			||||||
 | 
					 * to 'any' to be able to link with both old and new libraries.
 | 
				
			||||||
 | 
					 * Newer toolchains are capable of automatically generating this, but we want
 | 
				
			||||||
 | 
					 * to work with older toolchains as well. Therefore, we define the contents of
 | 
				
			||||||
 | 
					 * this section here (under different names), and then genvdso will patch
 | 
				
			||||||
 | 
					 * it to have the correct name and type.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We base the .MIPS.abiflags section on preprocessor definitions rather than
 | 
				
			||||||
 | 
					 * CONFIG_* because we need to match the particular ABI we are building the
 | 
				
			||||||
 | 
					 * VDSO for.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * See https://dmz-portal.mips.com/wiki/MIPS_O32_ABI_-_FR0_and_FR1_Interlinking
 | 
				
			||||||
 | 
					 * for the .MIPS.abiflags section description.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.section .mips_abiflags, "a"
 | 
				
			||||||
 | 
						.align 3
 | 
				
			||||||
 | 
					__mips_abiflags:
 | 
				
			||||||
 | 
						.hword	0		/* version */
 | 
				
			||||||
 | 
						.byte	__mips		/* isa_level */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* isa_rev */
 | 
				
			||||||
 | 
					#ifdef __mips_isa_rev
 | 
				
			||||||
 | 
						.byte	__mips_isa_rev
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						.byte	0
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* gpr_size */
 | 
				
			||||||
 | 
					#ifdef __mips64
 | 
				
			||||||
 | 
						.byte	2		/* AFL_REG_64 */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						.byte	1		/* AFL_REG_32 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* cpr1_size */
 | 
				
			||||||
 | 
					#if (defined(__mips_isa_rev) && __mips_isa_rev >= 6) || defined(__mips64)
 | 
				
			||||||
 | 
						.byte	2		/* AFL_REG_64 */
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						.byte	1		/* AFL_REG_32 */
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.byte	0		/* cpr2_size (AFL_REG_NONE) */
 | 
				
			||||||
 | 
						.byte	0		/* fp_abi (Val_GNU_MIPS_ABI_FP_ANY) */
 | 
				
			||||||
 | 
						.word	0		/* isa_ext */
 | 
				
			||||||
 | 
						.word	0		/* ases */
 | 
				
			||||||
 | 
						.word	0		/* flags1 */
 | 
				
			||||||
 | 
						.word	0		/* flags2 */
 | 
				
			||||||
							
								
								
									
										293
									
								
								arch/mips/vdso/genvdso.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										293
									
								
								arch/mips/vdso/genvdso.c
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,293 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * This tool is used to generate the real VDSO images from the raw image. It
 | 
				
			||||||
 | 
					 * first patches up the MIPS ABI flags and GNU attributes sections defined in
 | 
				
			||||||
 | 
					 * elf.S to have the correct name and type. It then generates a C source file
 | 
				
			||||||
 | 
					 * to be compiled into the kernel containing the VDSO image data and a
 | 
				
			||||||
 | 
					 * mips_vdso_image struct for it, including symbol offsets extracted from the
 | 
				
			||||||
 | 
					 * image.
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * We need to be passed both a stripped and unstripped VDSO image. The stripped
 | 
				
			||||||
 | 
					 * image is compiled into the kernel, but we must also patch up the unstripped
 | 
				
			||||||
 | 
					 * image's ABI flags sections so that it can be installed and used for
 | 
				
			||||||
 | 
					 * debugging.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <sys/mman.h>
 | 
				
			||||||
 | 
					#include <sys/stat.h>
 | 
				
			||||||
 | 
					#include <sys/types.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <byteswap.h>
 | 
				
			||||||
 | 
					#include <elf.h>
 | 
				
			||||||
 | 
					#include <errno.h>
 | 
				
			||||||
 | 
					#include <fcntl.h>
 | 
				
			||||||
 | 
					#include <inttypes.h>
 | 
				
			||||||
 | 
					#include <stdarg.h>
 | 
				
			||||||
 | 
					#include <stdbool.h>
 | 
				
			||||||
 | 
					#include <stdio.h>
 | 
				
			||||||
 | 
					#include <stdlib.h>
 | 
				
			||||||
 | 
					#include <string.h>
 | 
				
			||||||
 | 
					#include <unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Define these in case the system elf.h is not new enough to have them. */
 | 
				
			||||||
 | 
					#ifndef SHT_GNU_ATTRIBUTES
 | 
				
			||||||
 | 
					# define SHT_GNU_ATTRIBUTES	0x6ffffff5
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#ifndef SHT_MIPS_ABIFLAGS
 | 
				
			||||||
 | 
					# define SHT_MIPS_ABIFLAGS	0x7000002a
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					enum {
 | 
				
			||||||
 | 
						ABI_O32 = (1 << 0),
 | 
				
			||||||
 | 
						ABI_N32 = (1 << 1),
 | 
				
			||||||
 | 
						ABI_N64 = (1 << 2),
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						ABI_ALL = ABI_O32 | ABI_N32 | ABI_N64,
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Symbols the kernel requires offsets for. */
 | 
				
			||||||
 | 
					static struct {
 | 
				
			||||||
 | 
						const char *name;
 | 
				
			||||||
 | 
						const char *offset_name;
 | 
				
			||||||
 | 
						unsigned int abis;
 | 
				
			||||||
 | 
					} vdso_symbols[] = {
 | 
				
			||||||
 | 
						{ "__vdso_sigreturn", "off_sigreturn", ABI_O32 },
 | 
				
			||||||
 | 
						{ "__vdso_rt_sigreturn", "off_rt_sigreturn", ABI_ALL },
 | 
				
			||||||
 | 
						{}
 | 
				
			||||||
 | 
					};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static const char *program_name;
 | 
				
			||||||
 | 
					static const char *vdso_name;
 | 
				
			||||||
 | 
					static unsigned char elf_class;
 | 
				
			||||||
 | 
					static unsigned int elf_abi;
 | 
				
			||||||
 | 
					static bool need_swap;
 | 
				
			||||||
 | 
					static FILE *out_file;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if __BYTE_ORDER__ == __ORDER_LITTLE_ENDIAN__
 | 
				
			||||||
 | 
					# define HOST_ORDER		ELFDATA2LSB
 | 
				
			||||||
 | 
					#elif __BYTE_ORDER__ == __ORDER_BIG_ENDIAN__
 | 
				
			||||||
 | 
					# define HOST_ORDER		ELFDATA2MSB
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define BUILD_SWAP(bits)						\
 | 
				
			||||||
 | 
						static uint##bits##_t swap_uint##bits(uint##bits##_t val)	\
 | 
				
			||||||
 | 
						{								\
 | 
				
			||||||
 | 
							return need_swap ? bswap_##bits(val) : val;		\
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					BUILD_SWAP(16)
 | 
				
			||||||
 | 
					BUILD_SWAP(32)
 | 
				
			||||||
 | 
					BUILD_SWAP(64)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __FUNC(name, bits) name##bits
 | 
				
			||||||
 | 
					#define _FUNC(name, bits) __FUNC(name, bits)
 | 
				
			||||||
 | 
					#define FUNC(name) _FUNC(name, ELF_BITS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define __ELF(x, bits) Elf##bits##_##x
 | 
				
			||||||
 | 
					#define _ELF(x, bits) __ELF(x, bits)
 | 
				
			||||||
 | 
					#define ELF(x) _ELF(x, ELF_BITS)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Include genvdso.h twice with ELF_BITS defined differently to get functions
 | 
				
			||||||
 | 
					 * for both ELF32 and ELF64.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ELF_BITS 64
 | 
				
			||||||
 | 
					#include "genvdso.h"
 | 
				
			||||||
 | 
					#undef ELF_BITS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#define ELF_BITS 32
 | 
				
			||||||
 | 
					#include "genvdso.h"
 | 
				
			||||||
 | 
					#undef ELF_BITS
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static void *map_vdso(const char *path, size_t *_size)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						int fd;
 | 
				
			||||||
 | 
						struct stat stat;
 | 
				
			||||||
 | 
						void *addr;
 | 
				
			||||||
 | 
						const Elf32_Ehdr *ehdr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fd = open(path, O_RDWR);
 | 
				
			||||||
 | 
						if (fd < 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								path, strerror(errno));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (fstat(fd, &stat) != 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to stat '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								path, strerror(errno));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						addr = mmap(NULL, stat.st_size, PROT_READ | PROT_WRITE, MAP_SHARED, fd,
 | 
				
			||||||
 | 
							    0);
 | 
				
			||||||
 | 
						if (addr == MAP_FAILED) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to map '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								path, strerror(errno));
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* ELF32/64 header formats are the same for the bits we're checking. */
 | 
				
			||||||
 | 
						ehdr = addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (memcmp(ehdr->e_ident, ELFMAG, SELFMAG) != 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: '%s' is not an ELF file\n", program_name,
 | 
				
			||||||
 | 
								path);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						elf_class = ehdr->e_ident[EI_CLASS];
 | 
				
			||||||
 | 
						switch (elf_class) {
 | 
				
			||||||
 | 
						case ELFCLASS32:
 | 
				
			||||||
 | 
						case ELFCLASS64:
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: '%s' has invalid ELF class\n",
 | 
				
			||||||
 | 
								program_name, path);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						switch (ehdr->e_ident[EI_DATA]) {
 | 
				
			||||||
 | 
						case ELFDATA2LSB:
 | 
				
			||||||
 | 
						case ELFDATA2MSB:
 | 
				
			||||||
 | 
							need_swap = ehdr->e_ident[EI_DATA] != HOST_ORDER;
 | 
				
			||||||
 | 
							break;
 | 
				
			||||||
 | 
						default:
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: '%s' has invalid ELF data order\n",
 | 
				
			||||||
 | 
								program_name, path);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (swap_uint16(ehdr->e_machine) != EM_MIPS) {
 | 
				
			||||||
 | 
							fprintf(stderr,
 | 
				
			||||||
 | 
								"%s: '%s' has invalid ELF machine (expected EM_MIPS)\n",
 | 
				
			||||||
 | 
								program_name, path);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						} else if (swap_uint16(ehdr->e_type) != ET_DYN) {
 | 
				
			||||||
 | 
							fprintf(stderr,
 | 
				
			||||||
 | 
								"%s: '%s' has invalid ELF type (expected ET_DYN)\n",
 | 
				
			||||||
 | 
								program_name, path);
 | 
				
			||||||
 | 
							return NULL;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						*_size = stat.st_size;
 | 
				
			||||||
 | 
						return addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool patch_vdso(const char *path, void *vdso)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (elf_class == ELFCLASS64)
 | 
				
			||||||
 | 
							return patch_vdso64(path, vdso);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return patch_vdso32(path, vdso);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static bool get_symbols(const char *path, void *vdso)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						if (elf_class == ELFCLASS64)
 | 
				
			||||||
 | 
							return get_symbols64(path, vdso);
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							return get_symbols32(path, vdso);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					int main(int argc, char **argv)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const char *dbg_vdso_path, *vdso_path, *out_path;
 | 
				
			||||||
 | 
						void *dbg_vdso, *vdso;
 | 
				
			||||||
 | 
						size_t dbg_vdso_size, vdso_size, i;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						program_name = argv[0];
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (argc < 4 || argc > 5) {
 | 
				
			||||||
 | 
							fprintf(stderr,
 | 
				
			||||||
 | 
								"Usage: %s <debug VDSO> <stripped VDSO> <output file> [<name>]\n",
 | 
				
			||||||
 | 
								program_name);
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbg_vdso_path = argv[1];
 | 
				
			||||||
 | 
						vdso_path = argv[2];
 | 
				
			||||||
 | 
						out_path = argv[3];
 | 
				
			||||||
 | 
						vdso_name = (argc > 4) ? argv[4] : "";
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						dbg_vdso = map_vdso(dbg_vdso_path, &dbg_vdso_size);
 | 
				
			||||||
 | 
						if (!dbg_vdso)
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						vdso = map_vdso(vdso_path, &vdso_size);
 | 
				
			||||||
 | 
						if (!vdso)
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Patch both the VDSOs' ABI flags sections. */
 | 
				
			||||||
 | 
						if (!patch_vdso(dbg_vdso_path, dbg_vdso))
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						if (!patch_vdso(vdso_path, vdso))
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (msync(dbg_vdso, dbg_vdso_size, MS_SYNC) != 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								dbg_vdso_path, strerror(errno));
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						} else if (msync(vdso, vdso_size, MS_SYNC) != 0) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to sync '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								vdso_path, strerror(errno));
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						out_file = fopen(out_path, "w");
 | 
				
			||||||
 | 
						if (!out_file) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: Failed to open '%s': %s\n", program_name,
 | 
				
			||||||
 | 
								out_path, strerror(errno));
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(out_file, "/* Automatically generated - do not edit */\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "#include <linux/linkage.h>\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "#include <linux/mm.h>\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "#include <asm/vdso.h>\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Write out the stripped VDSO data. */
 | 
				
			||||||
 | 
						fprintf(out_file,
 | 
				
			||||||
 | 
							"static unsigned char vdso_data[PAGE_ALIGN(%zu)] __page_aligned_data = {\n\t",
 | 
				
			||||||
 | 
							vdso_size);
 | 
				
			||||||
 | 
						for (i = 0; i < vdso_size; i++) {
 | 
				
			||||||
 | 
							if (!(i % 10))
 | 
				
			||||||
 | 
								fprintf(out_file, "\n\t");
 | 
				
			||||||
 | 
							fprintf(out_file, "0x%02x, ", ((unsigned char *)vdso)[i]);
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
						fprintf(out_file, "\n};\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Preallocate a page array. */
 | 
				
			||||||
 | 
						fprintf(out_file,
 | 
				
			||||||
 | 
							"static struct page *vdso_pages[PAGE_ALIGN(%zu) / PAGE_SIZE];\n",
 | 
				
			||||||
 | 
							vdso_size);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(out_file, "struct mips_vdso_image vdso_image%s%s = {\n",
 | 
				
			||||||
 | 
							(vdso_name[0]) ? "_" : "", vdso_name);
 | 
				
			||||||
 | 
						fprintf(out_file, "\t.data = vdso_data,\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "\t.size = PAGE_ALIGN(%zu),\n", vdso_size);
 | 
				
			||||||
 | 
						fprintf(out_file, "\t.mapping = {\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "\t\t.name = \"[vdso]\",\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "\t\t.pages = vdso_pages,\n");
 | 
				
			||||||
 | 
						fprintf(out_file, "\t},\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Calculate and write symbol offsets to <output file> */
 | 
				
			||||||
 | 
						if (!get_symbols(dbg_vdso_path, dbg_vdso)) {
 | 
				
			||||||
 | 
							unlink(out_path);
 | 
				
			||||||
 | 
							return EXIT_FAILURE;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						fprintf(out_file, "};\n");
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return EXIT_SUCCESS;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										187
									
								
								arch/mips/vdso/genvdso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										187
									
								
								arch/mips/vdso/genvdso.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,187 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool FUNC(patch_vdso)(const char *path, void *vdso)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const ELF(Ehdr) *ehdr = vdso;
 | 
				
			||||||
 | 
						void *shdrs;
 | 
				
			||||||
 | 
						ELF(Shdr) *shdr;
 | 
				
			||||||
 | 
						char *shstrtab, *name;
 | 
				
			||||||
 | 
						uint16_t sh_count, sh_entsize, i;
 | 
				
			||||||
 | 
						unsigned int local_gotno, symtabno, gotsym;
 | 
				
			||||||
 | 
						ELF(Dyn) *dyn = NULL;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
 | 
				
			||||||
 | 
						sh_count = swap_uint16(ehdr->e_shnum);
 | 
				
			||||||
 | 
						sh_entsize = swap_uint16(ehdr->e_shentsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						shdr = shdrs + (sh_entsize * swap_uint16(ehdr->e_shstrndx));
 | 
				
			||||||
 | 
						shstrtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sh_count; i++) {
 | 
				
			||||||
 | 
							shdr = shdrs + (i * sh_entsize);
 | 
				
			||||||
 | 
							name = shstrtab + swap_uint32(shdr->sh_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/*
 | 
				
			||||||
 | 
							 * Ensure there are no relocation sections - ld.so does not
 | 
				
			||||||
 | 
							 * relocate the VDSO so if there are relocations things will
 | 
				
			||||||
 | 
							 * break.
 | 
				
			||||||
 | 
							 */
 | 
				
			||||||
 | 
							switch (swap_uint32(shdr->sh_type)) {
 | 
				
			||||||
 | 
							case SHT_REL:
 | 
				
			||||||
 | 
							case SHT_RELA:
 | 
				
			||||||
 | 
								fprintf(stderr,
 | 
				
			||||||
 | 
									"%s: '%s' contains relocation sections\n",
 | 
				
			||||||
 | 
									program_name, path);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							case SHT_DYNAMIC:
 | 
				
			||||||
 | 
								dyn = vdso + FUNC(swap_uint)(shdr->sh_offset);
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							/* Check for existing sections. */
 | 
				
			||||||
 | 
							if (strcmp(name, ".MIPS.abiflags") == 0) {
 | 
				
			||||||
 | 
								fprintf(stderr,
 | 
				
			||||||
 | 
									"%s: '%s' already contains a '.MIPS.abiflags' section\n",
 | 
				
			||||||
 | 
									program_name, path);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (strcmp(name, ".mips_abiflags") == 0) {
 | 
				
			||||||
 | 
								strcpy(name, ".MIPS.abiflags");
 | 
				
			||||||
 | 
								shdr->sh_type = swap_uint32(SHT_MIPS_ABIFLAGS);
 | 
				
			||||||
 | 
								shdr->sh_entsize = shdr->sh_size;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Ensure the GOT has no entries other than the standard 2, for the same
 | 
				
			||||||
 | 
						 * reason we check that there's no relocation sections above.
 | 
				
			||||||
 | 
						 * The standard two entries are:
 | 
				
			||||||
 | 
						 * - Lazy resolver
 | 
				
			||||||
 | 
						 * - Module pointer
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						if (dyn) {
 | 
				
			||||||
 | 
							local_gotno = symtabno = gotsym = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							while (FUNC(swap_uint)(dyn->d_tag) != DT_NULL) {
 | 
				
			||||||
 | 
								switch (FUNC(swap_uint)(dyn->d_tag)) {
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This member holds the number of local GOT entries.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								case DT_MIPS_LOCAL_GOTNO:
 | 
				
			||||||
 | 
									local_gotno = FUNC(swap_uint)(dyn->d_un.d_val);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This member holds the number of entries in the
 | 
				
			||||||
 | 
								 * .dynsym section.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								case DT_MIPS_SYMTABNO:
 | 
				
			||||||
 | 
									symtabno = FUNC(swap_uint)(dyn->d_un.d_val);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								/*
 | 
				
			||||||
 | 
								 * This member holds the index of the first dynamic
 | 
				
			||||||
 | 
								 * symbol table entry that corresponds to an entry in
 | 
				
			||||||
 | 
								 * the GOT.
 | 
				
			||||||
 | 
								 */
 | 
				
			||||||
 | 
								case DT_MIPS_GOTSYM:
 | 
				
			||||||
 | 
									gotsym = FUNC(swap_uint)(dyn->d_un.d_val);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								dyn++;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (local_gotno > 2 || symtabno - gotsym) {
 | 
				
			||||||
 | 
								fprintf(stderr,
 | 
				
			||||||
 | 
									"%s: '%s' contains unexpected GOT entries\n",
 | 
				
			||||||
 | 
									program_name, path);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline bool FUNC(get_symbols)(const char *path, void *vdso)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						const ELF(Ehdr) *ehdr = vdso;
 | 
				
			||||||
 | 
						void *shdrs, *symtab;
 | 
				
			||||||
 | 
						ELF(Shdr) *shdr;
 | 
				
			||||||
 | 
						const ELF(Sym) *sym;
 | 
				
			||||||
 | 
						char *strtab, *name;
 | 
				
			||||||
 | 
						uint16_t sh_count, sh_entsize, st_count, st_entsize, i, j;
 | 
				
			||||||
 | 
						uint64_t offset;
 | 
				
			||||||
 | 
						uint32_t flags;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						shdrs = vdso + FUNC(swap_uint)(ehdr->e_shoff);
 | 
				
			||||||
 | 
						sh_count = swap_uint16(ehdr->e_shnum);
 | 
				
			||||||
 | 
						sh_entsize = swap_uint16(ehdr->e_shentsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						for (i = 0; i < sh_count; i++) {
 | 
				
			||||||
 | 
							shdr = shdrs + (i * sh_entsize);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (swap_uint32(shdr->sh_type) == SHT_SYMTAB)
 | 
				
			||||||
 | 
								break;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						if (i == sh_count) {
 | 
				
			||||||
 | 
							fprintf(stderr, "%s: '%s' has no symbol table\n", program_name,
 | 
				
			||||||
 | 
								path);
 | 
				
			||||||
 | 
							return false;
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get flags */
 | 
				
			||||||
 | 
						flags = swap_uint32(ehdr->e_flags);
 | 
				
			||||||
 | 
						if (elf_class == ELFCLASS64)
 | 
				
			||||||
 | 
							elf_abi = ABI_N64;
 | 
				
			||||||
 | 
						else if (flags & EF_MIPS_ABI2)
 | 
				
			||||||
 | 
							elf_abi = ABI_N32;
 | 
				
			||||||
 | 
						else
 | 
				
			||||||
 | 
							elf_abi = ABI_O32;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get symbol table. */
 | 
				
			||||||
 | 
						symtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
 | 
				
			||||||
 | 
						st_entsize = FUNC(swap_uint)(shdr->sh_entsize);
 | 
				
			||||||
 | 
						st_count = FUNC(swap_uint)(shdr->sh_size) / st_entsize;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Get string table. */
 | 
				
			||||||
 | 
						shdr = shdrs + (swap_uint32(shdr->sh_link) * sh_entsize);
 | 
				
			||||||
 | 
						strtab = vdso + FUNC(swap_uint)(shdr->sh_offset);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/* Write offsets for symbols needed by the kernel. */
 | 
				
			||||||
 | 
						for (i = 0; vdso_symbols[i].name; i++) {
 | 
				
			||||||
 | 
							if (!(vdso_symbols[i].abis & elf_abi))
 | 
				
			||||||
 | 
								continue;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							for (j = 0; j < st_count; j++) {
 | 
				
			||||||
 | 
								sym = symtab + (j * st_entsize);
 | 
				
			||||||
 | 
								name = strtab + swap_uint32(sym->st_name);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
								if (!strcmp(name, vdso_symbols[i].name)) {
 | 
				
			||||||
 | 
									offset = FUNC(swap_uint)(sym->st_value);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
									fprintf(out_file,
 | 
				
			||||||
 | 
										"\t.%s = 0x%" PRIx64 ",\n",
 | 
				
			||||||
 | 
										vdso_symbols[i].offset_name, offset);
 | 
				
			||||||
 | 
									break;
 | 
				
			||||||
 | 
								}
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
							if (j == st_count) {
 | 
				
			||||||
 | 
								fprintf(stderr,
 | 
				
			||||||
 | 
									"%s: '%s' is missing required symbol '%s'\n",
 | 
				
			||||||
 | 
									program_name, path, vdso_symbols[i].name);
 | 
				
			||||||
 | 
								return false;
 | 
				
			||||||
 | 
							}
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return true;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
							
								
								
									
										49
									
								
								arch/mips/vdso/sigreturn.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										49
									
								
								arch/mips/vdso/sigreturn.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,49 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include "vdso.h"
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <uapi/asm/unistd.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/regdef.h>
 | 
				
			||||||
 | 
					#include <asm/asm.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.section	.text
 | 
				
			||||||
 | 
						.cfi_sections	.debug_frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LEAF(__vdso_rt_sigreturn)
 | 
				
			||||||
 | 
						.cfi_startproc
 | 
				
			||||||
 | 
						.frame	sp, 0, ra
 | 
				
			||||||
 | 
						.mask	0x00000000, 0
 | 
				
			||||||
 | 
						.fmask	0x00000000, 0
 | 
				
			||||||
 | 
						.cfi_signal_frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						li	v0, __NR_rt_sigreturn
 | 
				
			||||||
 | 
						syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.cfi_endproc
 | 
				
			||||||
 | 
						END(__vdso_rt_sigreturn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if _MIPS_SIM == _MIPS_SIM_ABI32
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					LEAF(__vdso_sigreturn)
 | 
				
			||||||
 | 
						.cfi_startproc
 | 
				
			||||||
 | 
						.frame	sp, 0, ra
 | 
				
			||||||
 | 
						.mask	0x00000000, 0
 | 
				
			||||||
 | 
						.fmask	0x00000000, 0
 | 
				
			||||||
 | 
						.cfi_signal_frame
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						li	v0, __NR_sigreturn
 | 
				
			||||||
 | 
						syscall
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.cfi_endproc
 | 
				
			||||||
 | 
						END(__vdso_sigreturn)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
							
								
								
									
										80
									
								
								arch/mips/vdso/vdso.h
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										80
									
								
								arch/mips/vdso/vdso.h
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,80 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/sgidefs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if _MIPS_SIM != _MIPS_SIM_ABI64 && defined(CONFIG_64BIT)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					/* Building 32-bit VDSO for the 64-bit kernel. Fake a 32-bit Kconfig. */
 | 
				
			||||||
 | 
					#undef CONFIG_64BIT
 | 
				
			||||||
 | 
					#define CONFIG_32BIT 1
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
 | 
					#include <asm-generic/atomic64.h>
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#ifndef __ASSEMBLY__
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/asm.h>
 | 
				
			||||||
 | 
					#include <asm/page.h>
 | 
				
			||||||
 | 
					#include <asm/vdso.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline unsigned long get_vdso_base(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						unsigned long addr;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * We can't use cpu_has_mips_r6 since it needs the cpu_data[]
 | 
				
			||||||
 | 
						 * kernel symbol.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					#ifdef CONFIG_CPU_MIPSR6
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * lapc <symbol> is an alias to addiupc reg, <symbol> - .
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 * We can't use addiupc because there is no label-label
 | 
				
			||||||
 | 
						 * support for the addiupc reloc
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						__asm__("lapc	%0, _start			\n"
 | 
				
			||||||
 | 
							: "=r" (addr) : :);
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Get the base load address of the VDSO. We have to avoid generating
 | 
				
			||||||
 | 
						 * relocations and references to the GOT because ld.so does not peform
 | 
				
			||||||
 | 
						 * relocations on the VDSO. We use the current offset from the VDSO base
 | 
				
			||||||
 | 
						 * and perform a PC-relative branch which gives the absolute address in
 | 
				
			||||||
 | 
						 * ra, and take the difference. The assembler chokes on
 | 
				
			||||||
 | 
						 * "li %0, _start - .", so embed the offset as a word and branch over
 | 
				
			||||||
 | 
						 * it.
 | 
				
			||||||
 | 
						 *
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						__asm__(
 | 
				
			||||||
 | 
						"	.set push				\n"
 | 
				
			||||||
 | 
						"	.set noreorder				\n"
 | 
				
			||||||
 | 
						"	bal	1f				\n"
 | 
				
			||||||
 | 
						"	 nop					\n"
 | 
				
			||||||
 | 
						"	.word	_start - .			\n"
 | 
				
			||||||
 | 
						"1:	lw	%0, 0($31)			\n"
 | 
				
			||||||
 | 
						"	" STR(PTR_ADDU) " %0, $31, %0		\n"
 | 
				
			||||||
 | 
						"	.set pop				\n"
 | 
				
			||||||
 | 
						: "=r" (addr)
 | 
				
			||||||
 | 
						:
 | 
				
			||||||
 | 
						: "$31");
 | 
				
			||||||
 | 
					#endif /* CONFIG_CPU_MIPSR6 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						return addr;
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					static inline const union mips_vdso_data *get_vdso_data(void)
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						return (const union mips_vdso_data *)(get_vdso_base() - PAGE_SIZE);
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#endif /* __ASSEMBLY__ */
 | 
				
			||||||
							
								
								
									
										100
									
								
								arch/mips/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										100
									
								
								arch/mips/vdso/vdso.lds.S
									
									
									
									
									
										Normal file
									
								
							| 
						 | 
					@ -0,0 +1,100 @@
 | 
				
			||||||
 | 
					/*
 | 
				
			||||||
 | 
					 * Copyright (C) 2015 Imagination Technologies
 | 
				
			||||||
 | 
					 * Author: Alex Smith <alex.smith@imgtec.com>
 | 
				
			||||||
 | 
					 *
 | 
				
			||||||
 | 
					 * 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;  either version 2 of the  License, or (at your
 | 
				
			||||||
 | 
					 * option) any later version.
 | 
				
			||||||
 | 
					 */
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#include <asm/sgidefs.h>
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					#if _MIPS_SIM == _MIPS_SIM_ABI64
 | 
				
			||||||
 | 
					OUTPUT_FORMAT("elf64-tradlittlemips", "elf64-tradbigmips", "elf64-tradlittlemips")
 | 
				
			||||||
 | 
					#elif _MIPS_SIM == _MIPS_SIM_NABI32
 | 
				
			||||||
 | 
					OUTPUT_FORMAT("elf32-ntradlittlemips", "elf32-ntradbigmips", "elf32-ntradlittlemips")
 | 
				
			||||||
 | 
					#else
 | 
				
			||||||
 | 
					OUTPUT_FORMAT("elf32-tradlittlemips", "elf32-tradbigmips", "elf32-tradlittlemips")
 | 
				
			||||||
 | 
					#endif
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					OUTPUT_ARCH(mips)
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					SECTIONS
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						PROVIDE(_start = .);
 | 
				
			||||||
 | 
						. = SIZEOF_HEADERS;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * In order to retain compatibility with older toolchains we provide the
 | 
				
			||||||
 | 
						 * ABI flags section ourself. Newer assemblers will automatically
 | 
				
			||||||
 | 
						 * generate .MIPS.abiflags sections so we discard such input sections,
 | 
				
			||||||
 | 
						 * and then manually define our own section here. genvdso will patch
 | 
				
			||||||
 | 
						 * this section to have the correct name/type.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						.mips_abiflags	: { *(.mips_abiflags) } 	:text :abiflags
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.reginfo	: { *(.reginfo) }		:text :reginfo
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.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
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.text		: { *(.text*) }			:text
 | 
				
			||||||
 | 
						PROVIDE (__etext = .);
 | 
				
			||||||
 | 
						PROVIDE (_etext = .);
 | 
				
			||||||
 | 
						PROVIDE (etext = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.eh_frame_hdr	: { *(.eh_frame_hdr) }		:text :eh_frame_hdr
 | 
				
			||||||
 | 
						.eh_frame	: { KEEP (*(.eh_frame)) }	:text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.dynamic	: { *(.dynamic) }		:text :dynamic
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						.rodata		: { *(.rodata*) }		:text
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						_end = .;
 | 
				
			||||||
 | 
						PROVIDE(end = .);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/DISCARD/	: {
 | 
				
			||||||
 | 
							*(.MIPS.abiflags)
 | 
				
			||||||
 | 
							*(.gnu.attributes)
 | 
				
			||||||
 | 
							*(.note.GNU-stack)
 | 
				
			||||||
 | 
							*(.data .data.* .gnu.linkonce.d.* .sdata*)
 | 
				
			||||||
 | 
							*(.bss .sbss .dynbss .dynsbss)
 | 
				
			||||||
 | 
						}
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					PHDRS
 | 
				
			||||||
 | 
					{
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * Provide a PT_MIPS_ABIFLAGS header to assign the ABI flags section
 | 
				
			||||||
 | 
						 * to. We can specify the header type directly here so no modification
 | 
				
			||||||
 | 
						 * is needed later on.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						abiflags	0x70000003;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						/*
 | 
				
			||||||
 | 
						 * The ABI flags header must exist directly after the PT_INTERP header,
 | 
				
			||||||
 | 
						 * so we must explicitly place the PT_MIPS_REGINFO header after it to
 | 
				
			||||||
 | 
						 * stop the linker putting one in at the start.
 | 
				
			||||||
 | 
						 */
 | 
				
			||||||
 | 
						reginfo		0x70000000;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
						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 {
 | 
				
			||||||
 | 
						local: *;
 | 
				
			||||||
 | 
						};
 | 
				
			||||||
 | 
					}
 | 
				
			||||||
		Loading…
	
		Reference in a new issue