Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 62360
b: refs/heads/master
c: 2aae950
h: refs/heads/master
v: v3
  • Loading branch information
Andi Kleen authored and Linus Torvalds committed Jul 22, 2007
1 parent 23dbfe3 commit ac79131
Show file tree
Hide file tree
Showing 24 changed files with 555 additions and 22 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: a586df067afe0580bb02b7a6312ca2afe49bba03
refs/heads/master: 2aae950b21e4bc789d1fc6668faf67e8748300b7
2 changes: 1 addition & 1 deletion trunk/Documentation/kernel-parameters.txt
Original file line number Diff line number Diff line change
Expand Up @@ -1882,7 +1882,7 @@ and is between 256 and 4096 characters. It is defined in the file
usbhid.mousepoll=
[USBHID] The interval which mice are to be polled at.

vdso= [IA-32,SH]
vdso= [IA-32,SH,x86-64]
vdso=2: enable compat VDSO (default with COMPAT_VDSO)
vdso=1: enable VDSO (default)
vdso=0: disable VDSO mapping
Expand Down
3 changes: 2 additions & 1 deletion trunk/arch/x86_64/Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -76,7 +76,8 @@ head-y := arch/x86_64/kernel/head.o arch/x86_64/kernel/head64.o arch/x86_64/kern
libs-y += arch/x86_64/lib/
core-y += arch/x86_64/kernel/ \
arch/x86_64/mm/ \
arch/x86_64/crypto/
arch/x86_64/crypto/ \
arch/x86_64/vdso/
core-$(CONFIG_IA32_EMULATION) += arch/x86_64/ia32/
drivers-$(CONFIG_PCI) += arch/x86_64/pci/
drivers-$(CONFIG_OPROFILE) += arch/x86_64/oprofile/
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/x86_64/ia32/ia32_binfmt.c
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@

int sysctl_vsyscall32 = 1;

#undef ARCH_DLINFO
#define ARCH_DLINFO do { \
if (sysctl_vsyscall32) { \
NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \
Expand Down
1 change: 1 addition & 0 deletions trunk/arch/x86_64/kernel/time.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@
#include <asm/hpet.h>
#include <asm/mpspec.h>
#include <asm/nmi.h>
#include <asm/vgtod.h>

static char *timename = NULL;

Expand Down
9 changes: 9 additions & 0 deletions trunk/arch/x86_64/kernel/vmlinux.lds.S
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,9 @@ SECTIONS
.vsyscall_gtod_data : AT(VLOAD(.vsyscall_gtod_data))
{ *(.vsyscall_gtod_data) }
vsyscall_gtod_data = VVIRT(.vsyscall_gtod_data);
.vsyscall_clock : AT(VLOAD(.vsyscall_clock))
{ *(.vsyscall_clock) }
vsyscall_clock = VVIRT(.vsyscall_clock);


.vsyscall_1 ADDR(.vsyscall_0) + 1024: AT(VLOAD(.vsyscall_1))
Expand Down Expand Up @@ -189,6 +192,12 @@ SECTIONS
.exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) }
.exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) }

/* vdso blob that is mapped into user space */
vdso_start = . ;
.vdso : AT(ADDR(.vdso) - LOAD_OFFSET) { *(.vdso) }
. = ALIGN(4096);
vdso_end = .;

#ifdef CONFIG_BLK_DEV_INITRD
. = ALIGN(4096);
__initramfs_start = .;
Expand Down
22 changes: 4 additions & 18 deletions trunk/arch/x86_64/kernel/vsyscall.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,7 @@
#include <asm/segment.h>
#include <asm/desc.h>
#include <asm/topology.h>
#include <asm/vgtod.h>

#define __vsyscall(nr) __attribute__ ((unused,__section__(".vsyscall_" #nr)))
#define __syscall_clobber "r11","rcx","memory"
Expand All @@ -57,26 +58,9 @@
* - writen by timer interrupt or systcl (/proc/sys/kernel/vsyscall64)
* Try to keep this structure as small as possible to avoid cache line ping pongs
*/
struct vsyscall_gtod_data_t {
seqlock_t lock;

/* open coded 'struct timespec' */
time_t wall_time_sec;
u32 wall_time_nsec;

int sysctl_enabled;
struct timezone sys_tz;
struct { /* extract of a clocksource struct */
cycle_t (*vread)(void);
cycle_t cycle_last;
cycle_t mask;
u32 mult;
u32 shift;
} clock;
};
int __vgetcpu_mode __section_vgetcpu_mode;

struct vsyscall_gtod_data_t __vsyscall_gtod_data __section_vsyscall_gtod_data =
struct vsyscall_gtod_data __vsyscall_gtod_data __section_vsyscall_gtod_data =
{
.lock = SEQLOCK_UNLOCKED,
.sysctl_enabled = 1,
Expand All @@ -96,6 +80,8 @@ void update_vsyscall(struct timespec *wall_time, struct clocksource *clock)
vsyscall_gtod_data.wall_time_sec = wall_time->tv_sec;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
vsyscall_gtod_data.sys_tz = sys_tz;
vsyscall_gtod_data.wall_time_nsec = wall_time->tv_nsec;
vsyscall_gtod_data.wall_to_monotonic = wall_to_monotonic;
write_sequnlock_irqrestore(&vsyscall_gtod_data.lock, flags);
}

Expand Down
9 changes: 9 additions & 0 deletions trunk/arch/x86_64/mm/init.c
Original file line number Diff line number Diff line change
Expand Up @@ -774,3 +774,12 @@ void *alloc_bootmem_high_node(pg_data_t *pgdat, unsigned long size)
return __alloc_bootmem_core(pgdat->bdata, size,
SMP_CACHE_BYTES, (4UL*1024*1024*1024), 0);
}

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]";
if (vma == &gate_vma)
return "[vsyscall]";
return NULL;
}
49 changes: 49 additions & 0 deletions trunk/arch/x86_64/vdso/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
#
# x86-64 vDSO.
#

# files to link into the vdso
# vdso-start.o has to be first
vobjs-y := vdso-start.o vdso-note.o vclock_gettime.o vgetcpu.o vvar.o

# files to link into kernel
obj-y := vma.o vdso.o vdso-syms.o

vobjs := $(foreach F,$(vobjs-y),$(obj)/$F)

$(obj)/vdso.o: $(obj)/vdso.so

targets += vdso.so vdso.lds $(vobjs-y) vdso-syms.o

# The DSO images are built using a special linker script.
quiet_cmd_syscall = SYSCALL $@
cmd_syscall = $(CC) -m elf_x86_64 -nostdlib $(SYSCFLAGS_$(@F)) \
-Wl,-T,$(filter-out FORCE,$^) -o $@

export CPPFLAGS_vdso.lds += -P -C -U$(ARCH)

vdso-flags = -fPIC -shared -Wl,-soname=linux-vdso.so.1 \
$(call ld-option, -Wl$(comma)--hash-style=sysv) \
-Wl,-z,max-page-size=4096 -Wl,-z,common-page-size=4096
SYSCFLAGS_vdso.so = $(vdso-flags)

$(obj)/vdso.o: $(src)/vdso.S $(obj)/vdso.so

$(obj)/vdso.so: $(src)/vdso.lds $(vobjs) FORCE
$(call if_changed,syscall)

CF := $(PROFILING) -mcmodel=small -fPIC -g0 -O2 -fasynchronous-unwind-tables -m64

$(obj)/vclock_gettime.o: CFLAGS = $(CF)
$(obj)/vgetcpu.o: CFLAGS = $(CF)

# We also create a special relocatable object that should mirror the symbol
# table and layout of the linked DSO. With ld -R we can then refer to
# these symbols in the kernel code rather than hand-coded addresses.
extra-y += vdso-syms.o
$(obj)/built-in.o: $(obj)/vdso-syms.o
$(obj)/built-in.o: ld_flags += -R $(obj)/vdso-syms.o

SYSCFLAGS_vdso-syms.o = -r -d
$(obj)/vdso-syms.o: $(src)/vdso.lds $(vobjs) FORCE
$(call if_changed,syscall)
120 changes: 120 additions & 0 deletions trunk/arch/x86_64/vdso/vclock_gettime.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
/*
* Copyright 2006 Andi Kleen, SUSE Labs.
* Subject to the GNU Public License, v.2
*
* Fast user context implementation of clock_gettime and gettimeofday.
*
* The code should have no internal unresolved relocations.
* Check with readelf after changing.
* Also alternative() doesn't work.
*/

#include <linux/kernel.h>
#include <linux/posix-timers.h>
#include <linux/time.h>
#include <linux/string.h>
#include <asm/vsyscall.h>
#include <asm/vgtod.h>
#include <asm/timex.h>
#include <asm/hpet.h>
#include <asm/unistd.h>
#include <asm/io.h>
#include <asm/vgtod.h>
#include "vextern.h"

#define gtod vdso_vsyscall_gtod_data

static long vdso_fallback_gettime(long clock, struct timespec *ts)
{
long ret;
asm("syscall" : "=a" (ret) :
"0" (__NR_clock_gettime),"D" (clock), "S" (ts) : "memory");
return ret;
}

static inline long vgetns(void)
{
cycles_t (*vread)(void);
vread = gtod->clock.vread;
return ((vread() - gtod->clock.cycle_last) * gtod->clock.mult) >>
gtod->clock.shift;
}

static noinline int do_realtime(struct timespec *ts)
{
unsigned long seq, ns;
do {
seq = read_seqbegin(&gtod->lock);
ts->tv_sec = gtod->wall_time_sec;
ts->tv_nsec = gtod->wall_time_nsec;
ns = vgetns();
} while (unlikely(read_seqretry(&gtod->lock, seq)));
timespec_add_ns(ts, ns);
return 0;
}

/* Copy of the version in kernel/time.c which we cannot directly access */
static void vset_normalized_timespec(struct timespec *ts, long sec, long nsec)
{
while (nsec >= NSEC_PER_SEC) {
nsec -= NSEC_PER_SEC;
++sec;
}
while (nsec < 0) {
nsec += NSEC_PER_SEC;
--sec;
}
ts->tv_sec = sec;
ts->tv_nsec = nsec;
}

static noinline int do_monotonic(struct timespec *ts)
{
unsigned long seq, ns, secs;
do {
seq = read_seqbegin(&gtod->lock);
secs = gtod->wall_time_sec;
ns = gtod->wall_time_nsec + vgetns();
secs += gtod->wall_to_monotonic.tv_sec;
ns += gtod->wall_to_monotonic.tv_nsec;
} while (unlikely(read_seqretry(&gtod->lock, seq)));
vset_normalized_timespec(ts, secs, ns);
return 0;
}

int __vdso_clock_gettime(clockid_t clock, struct timespec *ts)
{
if (likely(gtod->sysctl_enabled && gtod->clock.vread))
switch (clock) {
case CLOCK_REALTIME:
return do_realtime(ts);
case CLOCK_MONOTONIC:
return do_monotonic(ts);
}
return vdso_fallback_gettime(clock, ts);
}
int clock_gettime(clockid_t, struct timespec *)
__attribute__((weak, alias("__vdso_clock_gettime")));

int __vdso_gettimeofday(struct timeval *tv, struct timezone *tz)
{
long ret;
if (likely(gtod->sysctl_enabled && gtod->clock.vread)) {
BUILD_BUG_ON(offsetof(struct timeval, tv_usec) !=
offsetof(struct timespec, tv_nsec) ||
sizeof(*tv) != sizeof(struct timespec));
do_realtime((struct timespec *)tv);
tv->tv_usec /= 1000;
if (unlikely(tz != NULL)) {
/* This relies on gcc inlining the memcpy. We'll notice
if it ever fails to do so. */
memcpy(tz, &gtod->sys_tz, sizeof(struct timezone));
}
return 0;
}
asm("syscall" : "=a" (ret) :
"0" (__NR_gettimeofday), "D" (tv), "S" (tz) : "memory");
return ret;
}
int gettimeofday(struct timeval *, struct timezone *)
__attribute__((weak, alias("__vdso_gettimeofday")));
12 changes: 12 additions & 0 deletions trunk/arch/x86_64/vdso/vdso-note.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
/*
* This supplies .note.* sections to go into the PT_NOTE inside the vDSO text.
* Here we can supply some information useful to userland.
*/

#include <linux/uts.h>
#include <linux/version.h>
#include <linux/elfnote.h>

ELFNOTE_START(Linux, 0, "a")
.long LINUX_VERSION_CODE
ELFNOTE_END
2 changes: 2 additions & 0 deletions trunk/arch/x86_64/vdso/vdso-start.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.globl vdso_kernel_start
vdso_kernel_start:
2 changes: 2 additions & 0 deletions trunk/arch/x86_64/vdso/vdso.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
.section ".vdso","a"
.incbin "arch/x86_64/vdso/vdso.so"
77 changes: 77 additions & 0 deletions trunk/arch/x86_64/vdso/vdso.lds.S
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
/*
* Linker script for vsyscall DSO. The vsyscall page is an ELF shared
* object prelinked to its virtual address, and with only one read-only
* segment (that fits in one page). This script controls its layout.
*/
#include <asm/asm-offsets.h>
#include "voffset.h"

#define VDSO_PRELINK 0xffffffffff700000

SECTIONS
{
. = VDSO_PRELINK + 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) }

/* This linker script is used both with -r and with -shared.
For the layouts to match, we need to skip more than enough
space for the dynamic symbol table et al. If this amount
is insufficient, ld -shared will barf. Just increase it here. */
. = VDSO_PRELINK + VDSO_TEXT_OFFSET;

.text : { *(.text) } :text
.text.ptr : { *(.text.ptr) } :text
. = VDSO_PRELINK + 0x900;
.data : { *(.data) } :text
.bss : { *(.bss) } :text

.altinstructions : { *(.altinstructions) } :text
.altinstr_replacement : { *(.altinstr_replacement) } :text

.note : { *(.note.*) } :text :note
.eh_frame_hdr : { *(.eh_frame_hdr) } :text :eh_frame_hdr
.eh_frame : { KEEP (*(.eh_frame)) } :text
.dynamic : { *(.dynamic) } :text :dynamic
.useless : {
*(.got.plt) *(.got)
*(.gnu.linkonce.d.*)
*(.dynbss)
*(.gnu.linkonce.b.*)
} :text
}

/*
* 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 FILEHDR PHDRS FLAGS(5); /* PF_R|PF_X */
dynamic PT_DYNAMIC FLAGS(4); /* PF_R */
note PT_NOTE FLAGS(4); /* PF_R */
eh_frame_hdr 0x6474e550; /* PT_GNU_EH_FRAME, but ld doesn't match the name */
}

/*
* This controls what symbols we export from the DSO.
*/
VERSION
{
LINUX_2.6 {
global:
clock_gettime;
__vdso_clock_gettime;
gettimeofday;
__vdso_gettimeofday;
getcpu;
__vdso_getcpu;
local: *;
};
}
Loading

0 comments on commit ac79131

Please sign in to comment.