diff options
| author | Patrick Mooney <pmooney@pfmooney.com> | 2016-05-16 20:49:35 +0000 |
|---|---|---|
| committer | Patrick Mooney <pmooney@pfmooney.com> | 2016-05-16 20:49:35 +0000 |
| commit | d19cb1300ec66e8552d605a713e7b6dd6ba255f5 (patch) | |
| tree | a3bbb3f8d5bcee582c50fbf4f5ef425fd9a8ed2d /usr/src/uts/i86pc | |
| parent | a257e301376666442c2b655cf573c9d3e34b1ed5 (diff) | |
| download | illumos-joyent-d19cb1300ec66e8552d605a713e7b6dd6ba255f5.tar.gz | |
OS-5192 need faster clock_gettime
Reviewed by: Jerry Jelinek <jerry.jelinek@joyent.com>
Reviewed by: Robert Mustacchi <rm@joyent.com>
Reviewed by: Joshua M. Clulow <jmc@joyent.com>
Reviewed by: Ryan Zezeski <ryan@zinascii.com>
Diffstat (limited to 'usr/src/uts/i86pc')
| -rw-r--r-- | usr/src/uts/i86pc/Makefile.files | 3 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/ml/comm_page.s | 88 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/ml/offsets.in | 5 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/comm_page_util.c | 62 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/cpuid.c | 21 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/mlsetup.c | 10 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/mp_startup.c | 28 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/os/timestamp.c | 17 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/sys/comm_page.h | 101 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/sys/machparam.h | 5 | ||||
| -rw-r--r-- | usr/src/uts/i86pc/sys/tsc.h | 28 |
11 files changed, 347 insertions, 21 deletions
diff --git a/usr/src/uts/i86pc/Makefile.files b/usr/src/uts/i86pc/Makefile.files index 9829939b16..ef7a36d09c 100644 --- a/usr/src/uts/i86pc/Makefile.files +++ b/usr/src/uts/i86pc/Makefile.files @@ -23,6 +23,7 @@ # Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. # # Copyright (c) 2010, Intel Corporation. +# Copyright 2016 Joyent, Inc. # # This Makefile defines file modules in the directory uts/i86pc # and its children. These are the source files which are i86pc @@ -40,6 +41,8 @@ CORE_OBJS += \ cmi.o \ cmi_hw.o \ cms.o \ + comm_page.o \ + comm_page_util.o \ confunix.o \ cpu_idle.o \ cpuid.o \ diff --git a/usr/src/uts/i86pc/ml/comm_page.s b/usr/src/uts/i86pc/ml/comm_page.s new file mode 100644 index 0000000000..7ff803ea93 --- /dev/null +++ b/usr/src/uts/i86pc/ml/comm_page.s @@ -0,0 +1,88 @@ + +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#include <sys/asm_linkage.h> +#include <sys/asm_misc.h> +#include <sys/param.h> +#include <sys/comm_page.h> +#include <sys/tsc.h> + +#if defined(__lint) + +hrtime_t tsc_last; +hrtime_t tsc_resume_cap; +hrtime_t tsc_hrtime_base; +uint32_t tsc_max_delta; +volatile uint32_t hres_lock; +uint32_t tsc_type; +uint32_t nsec_scale; +int64_t hrestime_adj; +hrtime_t hres_last_tick; +uint32_t tsc_ncpu; +volatile timestruc_t hrestime; +hrtime_t tsc_sync_tick_delta[NCPU]; + +comm_page_t comm_page; + +#else /* defined(__lint) */ + +#include "assym.h" + +/* + * x86 Comm Page + * + * This is the definition for the comm page on x86. The purpose of this struct + * is to consolidate certain pieces of kernel state into one contiguous section + * of memory in order for it to be exposed (read-only) to userspace. The + * struct contents are defined by hand so that member variables will maintain + * their original symbols for use throughout the rest of the kernel. This + * layout must exactly match the C definition of comm_page_t. + * See: "uts/i86pc/sys/comm_page.h" + */ + + .data + DGDEF3(comm_page, COMM_PAGE_S_SIZE, 4096) + DGDEF2(tsc_last, 8) + .fill 1, 8, 0 + DGDEF2(tsc_hrtime_base, 8) + .fill 1, 8, 0 + DGDEF2(tsc_resume_cap, 8) + .fill 1, 8, 0 + DGDEF2(tsc_type, 4); + .fill 1, 4, _CONST(TSC_RDTSC_CPUID) + DGDEF2(tsc_max_delta, 4); + .fill 1, 4, 0 + DGDEF2(hres_lock, 4); + .fill 1, 4, 0 + DGDEF2(nsec_scale, 4); + .fill 1, 4, 0 + DGDEF2(hrestime_adj, 8) + .fill 1, 8, 0 + DGDEF2(hres_last_tick, 8) + .fill 1, 8, 0 + DGDEF2(tsc_ncpu, 4) + .fill 1, 4, 0 + /* _cp_pad */ + .fill 1, 4, 0 + DGDEF2(hrestime, _MUL(2, 8)) + .fill 2, 8, 0 + DGDEF2(tsc_sync_tick_delta, _MUL(NCPU, 8)) + .fill _CONST(NCPU), 8, 0 + + /* pad out the rest of the page from the struct end */ + .fill _CONST(COMM_PAGE_SIZE - COMM_PAGE_S_SIZE), 1, 0 + +#endif /* defined(__lint) */ diff --git a/usr/src/uts/i86pc/ml/offsets.in b/usr/src/uts/i86pc/ml/offsets.in index 4253c644c1..a1f83d3cf8 100644 --- a/usr/src/uts/i86pc/ml/offsets.in +++ b/usr/src/uts/i86pc/ml/offsets.in @@ -1,7 +1,7 @@ \ \ Copyright (c) 2004, 2010, Oracle and/or its affiliates. All rights reserved. \ Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved. -\ Copyright 2015 Joyent, Inc. +\ Copyright 2016 Joyent, Inc. \ \ CDDL HEADER START \ @@ -62,6 +62,7 @@ #include <sys/brand.h> #include <sys/fastboot.h> #include <sys/cpr_wakecode.h> +#include <sys/comm_page.h> proc PROCSIZE p_link @@ -470,3 +471,5 @@ wc_cpu WC_CPU_SIZE wc_wakecode wc_cpu + +comm_page_s COMM_PAGE_S_SIZE diff --git a/usr/src/uts/i86pc/os/comm_page_util.c b/usr/src/uts/i86pc/os/comm_page_util.c new file mode 100644 index 0000000000..3c635fe79b --- /dev/null +++ b/usr/src/uts/i86pc/os/comm_page_util.c @@ -0,0 +1,62 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + + +#include <sys/types.h> +#include <sys/thread.h> +#include <sys/proc.h> +#include <sys/mman.h> +#include <sys/vmsystm.h> +#include <vm/as.h> +#include <vm/seg_umap.h> + +#if defined(__x86) && !defined(__xpv) +#include <sys/comm_page.h> +#endif /* defined(__x86) && !defined(__xpv) */ + +/* + * Map in the comm page. + * + * The contents of the comm page are only defined on non-xpv x86 at this time. + * Furthermore, the data is only valid in userspace (32-bit or 64-bit) when + * mapped from a 64-bit kernel. + * See: "uts/i86pc/sys/comm_page.h" + */ +caddr_t +comm_page_mapin() +{ +#if defined(__amd64) && !defined(__xpv) + proc_t *p = curproc; + caddr_t addr = NULL; + size_t len = COMM_PAGE_SIZE; + uint_t prot = PROT_USER | PROT_READ; + segumap_crargs_t suarg; + + map_addr(&addr, len, (offset_t)0, 1, 0); + if (addr == NULL || valid_usr_range(addr, len, prot, p->p_as, + p->p_as->a_userlimit) != RANGE_OKAY) { + return (NULL); + } + + suarg.kaddr = (caddr_t)&comm_page; + suarg.prot = suarg.maxprot = prot; + if (as_map(p->p_as, addr, len, segumap_create, &suarg) != 0) { + return (NULL); + } + return (addr); +#else /* defined(__amd64) && !defined(__xpv) */ + return (NULL); +#endif /* defined(__amd64) && !defined(__xpv) */ +} diff --git a/usr/src/uts/i86pc/os/cpuid.c b/usr/src/uts/i86pc/os/cpuid.c index 9b55ba9553..027ed29c3d 100644 --- a/usr/src/uts/i86pc/os/cpuid.c +++ b/usr/src/uts/i86pc/os/cpuid.c @@ -32,7 +32,7 @@ * Portions Copyright 2009 Advanced Micro Devices, Inc. */ /* - * Copyright (c) 2015, Joyent, Inc. All rights reserved. + * Copyright 2016 Joyent, Inc. */ /* * Various routines to handle identification @@ -57,6 +57,8 @@ #include <sys/auxv_386.h> #include <sys/memnode.h> #include <sys/pci_cfgspace.h> +#include <sys/comm_page.h> +#include <sys/tsc.h> #ifdef __xpv #include <sys/hypervisor.h> @@ -4614,27 +4616,30 @@ patch_tsc_read(int flag) size_t cnt; switch (flag) { - case X86_NO_TSC: + case TSC_NONE: cnt = &_no_rdtsc_end - &_no_rdtsc_start; (void) memcpy((void *)tsc_read, (void *)&_no_rdtsc_start, cnt); break; - case X86_HAVE_TSCP: - cnt = &_tscp_end - &_tscp_start; - (void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt); - break; - case X86_TSC_MFENCE: + case TSC_RDTSC_MFENCE: cnt = &_tsc_mfence_end - &_tsc_mfence_start; (void) memcpy((void *)tsc_read, (void *)&_tsc_mfence_start, cnt); break; - case X86_TSC_LFENCE: + case TSC_RDTSC_LFENCE: cnt = &_tsc_lfence_end - &_tsc_lfence_start; (void) memcpy((void *)tsc_read, (void *)&_tsc_lfence_start, cnt); break; + case TSC_TSCP: + cnt = &_tscp_end - &_tscp_start; + (void) memcpy((void *)tsc_read, (void *)&_tscp_start, cnt); + break; default: + /* Bail for unexpected TSC types. (TSC_NONE covers 0) */ + cmn_err(CE_PANIC, "Unrecogized TSC type: %d", flag); break; } + tsc_type = flag; } int diff --git a/usr/src/uts/i86pc/os/mlsetup.c b/usr/src/uts/i86pc/os/mlsetup.c index 045adbcb7b..438f83b6e9 100644 --- a/usr/src/uts/i86pc/os/mlsetup.c +++ b/usr/src/uts/i86pc/os/mlsetup.c @@ -23,6 +23,7 @@ * * Copyright (c) 1993, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2011 by Delphix. All rights reserved. + * Copyright 2016 Joyent, Inc. */ /* * Copyright (c) 2010, Intel Corporation. @@ -61,6 +62,7 @@ #include <sys/promif.h> #include <sys/pci_cfgspace.h> #include <sys/bootvfs.h> +#include <sys/tsc.h> #ifdef __xpv #include <sys/hypervisor.h> #else @@ -227,15 +229,15 @@ mlsetup(struct regs *rp) */ if ((get_hwenv() & HW_XEN_HVM) == 0 && is_x86_feature(x86_featureset, X86FSET_TSCP)) - patch_tsc_read(X86_HAVE_TSCP); + patch_tsc_read(TSC_TSCP); else if (cpuid_getvendor(CPU) == X86_VENDOR_AMD && cpuid_getfamily(CPU) <= 0xf && is_x86_feature(x86_featureset, X86FSET_SSE2)) - patch_tsc_read(X86_TSC_MFENCE); + patch_tsc_read(TSC_RDTSC_MFENCE); else if (cpuid_getvendor(CPU) == X86_VENDOR_Intel && cpuid_getfamily(CPU) <= 6 && is_x86_feature(x86_featureset, X86FSET_SSE2)) - patch_tsc_read(X86_TSC_LFENCE); + patch_tsc_read(TSC_RDTSC_LFENCE); #endif /* !__xpv */ @@ -246,7 +248,7 @@ mlsetup(struct regs *rp) * return 0. */ if (!is_x86_feature(x86_featureset, X86FSET_TSC)) - patch_tsc_read(X86_NO_TSC); + patch_tsc_read(TSC_NONE); #endif /* __i386 && !__xpv */ #if defined(__amd64) && !defined(__xpv) diff --git a/usr/src/uts/i86pc/os/mp_startup.c b/usr/src/uts/i86pc/os/mp_startup.c index 6ded04c1b5..829c631096 100644 --- a/usr/src/uts/i86pc/os/mp_startup.c +++ b/usr/src/uts/i86pc/os/mp_startup.c @@ -27,7 +27,7 @@ * All rights reserved. */ /* - * Copyright 2015 Joyent, Inc. + * Copyright 2016 Joyent, Inc. * Copyright 2013 Nexenta Systems, Inc. All rights reserved. */ @@ -249,6 +249,24 @@ init_cpu_syscall(struct cpu *cp) kpreempt_enable(); } +#if !defined(__xpv) +/* + * Configure per-cpu ID GDT + */ +static void +init_cpu_id_gdt(struct cpu *cp) +{ + /* Write cpu_id into limit field of GDT for usermode retrieval */ +#if defined(__amd64) + set_usegd(&cp->cpu_gdt[GDT_CPUID], SDP_SHORT, NULL, cp->cpu_id, + SDT_MEMRODA, SEL_UPL, SDP_BYTES, SDP_OP32); +#elif defined(__i386) + set_usegd(&cp->cpu_gdt[GDT_CPUID], NULL, cp->cpu_id, SDT_MEMRODA, + SEL_UPL, SDP_BYTES, SDP_OP32); +#endif +} +#endif /* !defined(__xpv) */ + /* * Multiprocessor initialization. * @@ -432,6 +450,10 @@ mp_cpu_configure_common(int cpun, boolean_t boot) init_cpu_info(cp); +#if !defined(__xpv) + init_cpu_id_gdt(cp); +#endif + /* * alloc space for ucode_info */ @@ -1488,6 +1510,10 @@ start_other_cpus(int cprboot) */ init_cpu_info(CPU); +#if !defined(__xpv) + init_cpu_id_gdt(CPU); +#endif + cmn_err(CE_CONT, "?cpu%d: %s\n", CPU->cpu_id, CPU->cpu_idstr); cmn_err(CE_CONT, "?cpu%d: %s\n", CPU->cpu_id, CPU->cpu_brandstr); diff --git a/usr/src/uts/i86pc/os/timestamp.c b/usr/src/uts/i86pc/os/timestamp.c index 3b478853ee..7344e1a492 100644 --- a/usr/src/uts/i86pc/os/timestamp.c +++ b/usr/src/uts/i86pc/os/timestamp.c @@ -25,7 +25,7 @@ * * Copyright 2012 Nexenta Systems, Inc. All rights reserved. * Copyright (c) 2014, 2016 by Delphix. All rights reserved. - * Copyright 2016 Joyent, Inc + * Copyright 2016 Joyent, Inc. */ #include <sys/types.h> @@ -48,6 +48,7 @@ #include <sys/panic.h> #include <sys/cpu.h> #include <sys/sdt.h> +#include <sys/comm_page.h> /* * Using the Pentium's TSC register for gethrtime() @@ -100,7 +101,6 @@ #define NSEC_SHIFT 5 -static uint_t nsec_scale; static uint_t nsec_unscale; /* @@ -141,16 +141,12 @@ static volatile int tsc_sync_go; int tsc_master_slave_sync_needed = 1; -static int tsc_max_delta; -static hrtime_t tsc_sync_tick_delta[NCPU]; typedef struct tsc_sync { volatile hrtime_t master_tsc, slave_tsc; } tsc_sync_t; static tsc_sync_t *tscp; -static hrtime_t tsc_last = 0; static hrtime_t tsc_last_jumped = 0; -static hrtime_t tsc_hrtime_base = 0; static int tsc_jumped = 0; static uint32_t tsc_wayback = 0; /* @@ -158,7 +154,6 @@ static uint32_t tsc_wayback = 0; * tsc_tick() function runs which means that when gethrtime() is called it * should never be more than 1 second since tsc_last was updated. */ -static hrtime_t tsc_resume_cap; static hrtime_t tsc_resume_cap_ns = NANOSEC; /* 1s */ static hrtime_t shadow_tsc_hrtime_base; @@ -541,6 +536,7 @@ tsc_sync_master(processorid_t slave) if (last_delta > min_write_time) { gethrtimef = tsc_gethrtime_delta; gethrtimeunscaledf = tsc_gethrtimeunscaled_delta; + tsc_ncpu = NCPU; } restore_int_flag(flags); } @@ -682,6 +678,12 @@ tsc_hrtimeinit(uint64_t cpu_freq_hz) hrtime_tick = tsc_tick; gethrtime_hires = 1; /* + * Being part of the comm page, tsc_ncpu communicates the published + * length of the tsc_sync_tick_delta array. This is kept zeroed to + * ignore the absent delta data while the TSCs are synced. + */ + tsc_ncpu = 0; + /* * Allocate memory for the structure used in the tsc sync logic. * This structure should be aligned on a multiple of cache line size. */ @@ -718,6 +720,7 @@ tsc_adjust_delta(hrtime_t tdelta) gethrtimef = tsc_gethrtime_delta; gethrtimeunscaledf = tsc_gethrtimeunscaled_delta; + tsc_ncpu = NCPU; } /* diff --git a/usr/src/uts/i86pc/sys/comm_page.h b/usr/src/uts/i86pc/sys/comm_page.h new file mode 100644 index 0000000000..9d94a27763 --- /dev/null +++ b/usr/src/uts/i86pc/sys/comm_page.h @@ -0,0 +1,101 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#ifndef _COMM_PAGE_H +#define _COMM_PAGE_H + +#ifndef _ASM +#include <sys/types.h> +#include <sys/param.h> +#include <sys/time.h> +#endif /* _ASM */ + +#ifdef __cplusplus +extern "C" { +#endif + +#define COMM_PAGE_SIZE PAGESIZE + +#ifndef _ASM + +/* + * x86 comm page + * + * This struct defines the data format for the "comm page": kernel data made + * directly available to userspace for read-only operations. This enables + * facilities such as clock_gettime to operate entirely in userspace without + * the need for a trap or fasttrap. + * + * A note about 32-bit/64-bit compatibility: + * The current format of the comm page is designed to be consistent for both + * 32-bit and 64-bit programs running in a 64-bit kernel. On 32-bit kernels, + * the comm page is not exposed to userspace due to the difference in + * timespec_t sizing. + * + * This struct is instantiated "by hand" in assembly to preserve the global + * symbols it contains. That layout must be kept in sync with the structure + * defined here. + * See: "uts/i86pc/ml/comm_page.s" + */ +typedef struct comm_page_s { + hrtime_t cp_tsc_last; + hrtime_t cp_tsc_hrtime_base; + hrtime_t cp_tsc_resume_cap; + uint32_t cp_tsc_type; + uint32_t cp_tsc_max_delta; + + volatile uint32_t cp_hres_lock; /* must be 8-byte aligned */ + uint32_t cp_nsec_scale; + int64_t cp_hrestime_adj; + hrtime_t cp_hres_last_tick; + uint32_t cp_tsc_ncpu; + uint32_t _cp_pad; + volatile int64_t cp_hrestime[2]; +#if defined(_MACHDEP) + hrtime_t cp_tsc_sync_tick_delta[NCPU]; +#else + /* length resides in cp_ncpu */ + hrtime_t cp_tsc_sync_tick_delta[]; +#endif /* defined(_MACHDEP) */ +} comm_page_t; + +#if defined(_KERNEL) +extern comm_page_t comm_page; + +extern caddr_t comm_page_mapin(); + +#if defined(_MACHDEP) +extern hrtime_t tsc_last; +extern hrtime_t tsc_hrtime_base; +extern hrtime_t tsc_resume_cap; +extern uint32_t tsc_type; +extern uint32_t tsc_max_delta; +extern volatile uint32_t hres_lock; +extern uint32_t nsec_scale; +extern int64_t hrestime_adj; +extern hrtime_t hres_last_tick; +extern uint32_t tsc_ncpu; +extern volatile timestruc_t hrestime; +extern hrtime_t tsc_sync_tick_delta[NCPU]; +#endif /* defined(_MACHDEP) */ +#endif /* defined(_KERNEL) */ + +#endif /* _ASM */ + +#ifdef __cplusplus +} +#endif + +#endif /* _COMM_PAGE_H */ diff --git a/usr/src/uts/i86pc/sys/machparam.h b/usr/src/uts/i86pc/sys/machparam.h index 99ae0d4d3b..fc34522307 100644 --- a/usr/src/uts/i86pc/sys/machparam.h +++ b/usr/src/uts/i86pc/sys/machparam.h @@ -21,6 +21,7 @@ /* * Copyright (c) 1992, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright (c) 2015 by Delphix. All rights reserved. + * Copyright 2016 Joyent, Inc. */ /* Copyright (c) 1988 AT&T */ @@ -54,6 +55,10 @@ extern "C" { */ #if defined(__amd64) +/* + * If NCPU grows beyond 256, sizing for the x86 comm page will require + * adjustment. + */ #define NCPU 256 #define NCPU_LOG2 8 #elif defined(__i386) diff --git a/usr/src/uts/i86pc/sys/tsc.h b/usr/src/uts/i86pc/sys/tsc.h new file mode 100644 index 0000000000..d4090381c4 --- /dev/null +++ b/usr/src/uts/i86pc/sys/tsc.h @@ -0,0 +1,28 @@ +/* + * This file and its contents are supplied under the terms of the + * Common Development and Distribution License ("CDDL"), version 1.0. + * You may only use this file in accordance with the terms of version + * 1.0 of the CDDL. + * + * A full copy of the text of the CDDL should have accompanied this + * source. A copy of the CDDL is also available via the Internet at + * http://www.illumos.org/license/CDDL. + */ + +/* + * Copyright 2016 Joyent, Inc. + */ + +#ifndef _TSC_H +#define _TSC_H + +/* + * flags to patch tsc_read routine. + */ +#define TSC_NONE 0x0 +#define TSC_RDTSC_CPUID 0x1 +#define TSC_RDTSC_MFENCE 0x2 +#define TSC_RDTSC_LFENCE 0x3 +#define TSC_TSCP 0x4 + +#endif /* _TSC_H */ |
