linux(4): Implement vdso getcpu for x86.
This is modeled after f2395455
(by kib@).
MFC after: 2 weeks
This commit is contained in:
parent
332eca05b5
commit
5a6a4fb284
@ -172,6 +172,7 @@ LINUX_VDSO_SYM_INTPTR(linux_rt_sigcode);
|
||||
LINUX_VDSO_SYM_CHAR(linux_platform);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_tsc_selector);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_cpu_selector);
|
||||
|
||||
/*
|
||||
* If FreeBSD & Linux have a difference of opinion about what a trap
|
||||
@ -837,6 +838,12 @@ linux_exec_sysvec_init(void *param)
|
||||
*ktsc_selector = linux_vdso_tsc_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux x86-64 vDSO tsc_selector: %lu\n", *ktsc_selector);
|
||||
|
||||
tkoff = kern_cpu_selector - linux_vdso_base;
|
||||
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
|
||||
*ktsc_selector = linux_vdso_cpu_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux x86-64 vDSO cpu_selector: %lu\n", *ktsc_selector);
|
||||
}
|
||||
SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY,
|
||||
linux_exec_sysvec_init, &elf_linux_sysvec);
|
||||
|
@ -68,6 +68,7 @@ VERSION
|
||||
linux_platform;
|
||||
kern_timekeep_base;
|
||||
kern_tsc_selector;
|
||||
kern_cpu_selector;
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
@ -49,8 +49,10 @@ __FBSDID("$FreeBSD$");
|
||||
/* The kernel fixup this at vDSO install */
|
||||
uintptr_t *kern_timekeep_base = NULL;
|
||||
uint32_t kern_tsc_selector = 0;
|
||||
uint32_t kern_cpu_selector = 0;
|
||||
|
||||
#include <x86/linux/linux_vdso_gettc_x86.inc>
|
||||
#include <x86/linux/linux_vdso_getcpu_x86.inc>
|
||||
|
||||
/* for debug purpose */
|
||||
static int
|
||||
|
@ -185,6 +185,7 @@ LINUX_VDSO_SYM_INTPTR(__kernel_sigreturn);
|
||||
LINUX_VDSO_SYM_INTPTR(__kernel_rt_sigreturn);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_tsc_selector);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_cpu_selector);
|
||||
LINUX_VDSO_SYM_CHAR(linux_platform);
|
||||
|
||||
/*
|
||||
@ -1000,6 +1001,12 @@ linux_exec_sysvec_init(void *param)
|
||||
*ktsc_selector = linux_vdso_tsc_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux i386 vDSO tsc_selector: %u\n", *ktsc_selector);
|
||||
|
||||
tkoff = kern_cpu_selector - linux_vdso_base;
|
||||
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
|
||||
*ktsc_selector = linux_vdso_cpu_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux i386 vDSO cpu_selector: %u\n", *ktsc_selector);
|
||||
}
|
||||
SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY,
|
||||
linux_exec_sysvec_init, &elf_linux_sysvec);
|
||||
|
@ -58,6 +58,7 @@ VERSION
|
||||
__vdso_clock_gettime;
|
||||
__vdso_gettimeofday;
|
||||
__vdso_time;
|
||||
__vdso_getcpu;
|
||||
__vdso_clock_getres;
|
||||
__vdso_clock_gettime64;
|
||||
};
|
||||
@ -75,6 +76,7 @@ VERSION
|
||||
linux_platform;
|
||||
kern_timekeep_base;
|
||||
kern_tsc_selector;
|
||||
kern_cpu_selector;
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
@ -50,8 +50,10 @@ __FBSDID("$FreeBSD$");
|
||||
/* The kernel fixup this at vDSO install */
|
||||
uintptr_t *kern_timekeep_base = NULL;
|
||||
uint32_t kern_tsc_selector = 0;
|
||||
uint32_t kern_cpu_selector = 0;
|
||||
|
||||
#include <x86/linux/linux_vdso_gettc_x86.inc>
|
||||
#include <x86/linux/linux_vdso_getcpu_x86.inc>
|
||||
|
||||
static int
|
||||
write(int fd, const void *buf, size_t size)
|
||||
@ -128,6 +130,21 @@ __vdso_clock_getres_fallback(clockid_t clock_id, struct l_timespec *ts)
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_getcpu_fallback(uint32_t *cpu, uint32_t *node, void *cache)
|
||||
{
|
||||
int res;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"int $0x80"
|
||||
: "=a"(res)
|
||||
: "a"(LINUX32_SYS_linux_getcpu), "D"(cpu), "S"(node), "d"(cache)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_time_fallback(long *tm)
|
||||
{
|
||||
|
@ -352,12 +352,19 @@ int clock_gettime64(clockid_t clock_id, struct l_timespec64 *lts)
|
||||
__attribute__((weak, alias("__vdso_clock_gettime64")));
|
||||
#endif
|
||||
|
||||
#if defined(__amd64__) && !defined(COMPAT_LINUX32)
|
||||
#if defined(__i386__) || defined(__amd64__)
|
||||
int
|
||||
__vdso_getcpu(uint32_t *cpu, uint32_t *node, void *cache)
|
||||
{
|
||||
int ret;
|
||||
|
||||
return (__vdso_getcpu_fallback(cpu, node, cache));
|
||||
if (node != NULL)
|
||||
return (__vdso_getcpu_fallback(cpu, node, cache));
|
||||
ret = __vdso_getcpu_try();
|
||||
if (ret < 0)
|
||||
return (__vdso_getcpu_fallback(cpu, node, cache));
|
||||
*cpu = ret;
|
||||
return (0);
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -160,6 +160,7 @@ LINUX_VDSO_SYM_INTPTR(__kernel_sigreturn);
|
||||
LINUX_VDSO_SYM_INTPTR(__kernel_rt_sigreturn);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_timekeep_base);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_tsc_selector);
|
||||
LINUX_VDSO_SYM_INTPTR(kern_cpu_selector);
|
||||
|
||||
/*
|
||||
* If FreeBSD & Linux have a difference of opinion about what a trap
|
||||
@ -942,6 +943,12 @@ linux_exec_sysvec_init(void *param)
|
||||
*ktsc_selector = linux_vdso_tsc_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux i386 vDSO tsc_selector: %u\n", *ktsc_selector);
|
||||
|
||||
tkoff = kern_cpu_selector - linux_vdso_base;
|
||||
ktsc_selector = (l_uintptr_t *)(linux_vdso_mapping + tkoff);
|
||||
*ktsc_selector = linux_vdso_cpu_selector_idx();
|
||||
if (bootverbose)
|
||||
printf("Linux i386 vDSO cpu_selector: %u\n", *ktsc_selector);
|
||||
}
|
||||
SYSINIT(elf_linux_exec_sysvec_init, SI_SUB_EXEC + 1, SI_ORDER_ANY,
|
||||
linux_exec_sysvec_init, &elf_linux_sysvec);
|
||||
|
@ -58,6 +58,7 @@ VERSION
|
||||
__vdso_clock_gettime;
|
||||
__vdso_gettimeofday;
|
||||
__vdso_time;
|
||||
__vdso_getcpu;
|
||||
__vdso_clock_getres;
|
||||
__vdso_clock_gettime64;
|
||||
};
|
||||
@ -75,6 +76,7 @@ VERSION
|
||||
linux_platform;
|
||||
kern_timekeep_base;
|
||||
kern_tsc_selector;
|
||||
kern_cpu_selector;
|
||||
local: *;
|
||||
};
|
||||
}
|
||||
|
@ -49,8 +49,10 @@ __FBSDID("$FreeBSD$");
|
||||
/* The kernel fixup this at vDSO install */
|
||||
uintptr_t *kern_timekeep_base = NULL;
|
||||
uint32_t kern_tsc_selector = 0;
|
||||
uint32_t kern_cpu_selector = 0;
|
||||
|
||||
#include <x86/linux/linux_vdso_gettc_x86.inc>
|
||||
#include <x86/linux/linux_vdso_getcpu_x86.inc>
|
||||
|
||||
static int
|
||||
write(int fd, const void *buf, size_t size)
|
||||
@ -127,6 +129,21 @@ __vdso_clock_getres_fallback(clockid_t clock_id, struct l_timespec *ts)
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_getcpu_fallback(uint32_t *cpu, uint32_t *node, void *cache)
|
||||
{
|
||||
int res;
|
||||
|
||||
__asm__ __volatile__
|
||||
(
|
||||
"int $0x80"
|
||||
: "=a"(res)
|
||||
: "a"(LINUX_SYS_linux_getcpu), "D"(cpu), "S"(node), "d"(cache)
|
||||
: "cc", "memory"
|
||||
);
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_time_fallback(long *tm)
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ SRCS= linux_fork.c linux${SFX}_dummy_machdep.c linux_file.c linux_event.c \
|
||||
opt_inet6.h opt_compat.h opt_posix.h opt_usb.h vnode_if.h \
|
||||
device_if.h bus_if.h
|
||||
.if ${MACHINE_CPUARCH} == "i386" || ${MACHINE_CPUARCH} == "amd64"
|
||||
SRCS+= linux_dummy_x86.c linux_vdso_tsc_selector_x86.c
|
||||
SRCS+= linux_dummy_x86.c linux_vdso_selector_x86.c
|
||||
VDSODEPS=linux_vdso_gettc_x86.inc
|
||||
.endif
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
|
@ -15,7 +15,7 @@ SRCS= linux_elf64.c linux_fork.c linux_dummy_machdep.c linux_file.c \
|
||||
vnode_if.h device_if.h bus_if.h \
|
||||
linux_support.s
|
||||
.if ${MACHINE_CPUARCH} == "amd64"
|
||||
SRCS+= linux_dummy_x86.c linux_vdso_tsc_selector_x86.c
|
||||
SRCS+= linux_dummy_x86.c linux_vdso_selector_x86.c
|
||||
.endif
|
||||
DPSRCS= assym.inc linux_genassym.c
|
||||
|
||||
|
68
sys/x86/linux/linux_vdso_getcpu_x86.inc
Normal file
68
sys/x86/linux/linux_vdso_getcpu_x86.inc
Normal file
@ -0,0 +1,68 @@
|
||||
/*-
|
||||
* SPDX-License-Identifier: BSD-2-Clause-FreeBSD
|
||||
*
|
||||
* Copyright (c) 2021 The FreeBSD Foundation
|
||||
* Copyright (c) 2022 Dmitry Chagin <dchagin@FreeBSD.org>
|
||||
*
|
||||
* Portions of this software were developed by Konstantin Belousov
|
||||
* under sponsorship from the FreeBSD Foundation.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
|
||||
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
||||
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
|
||||
* ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
|
||||
* FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
* DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
|
||||
* OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
|
||||
* LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
|
||||
* OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
|
||||
* SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <x86/linux/linux_x86.h>
|
||||
|
||||
static int
|
||||
__vdso_getcpu_rdpid(void)
|
||||
{
|
||||
register_t res;
|
||||
|
||||
__asm("rdpid %0" : "=r" (res));
|
||||
return ((int)res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_getcpu_rdtscp(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
__asm("rdtscp" : "=c" (res) : : "eax", "edx");
|
||||
return (res);
|
||||
}
|
||||
|
||||
static int
|
||||
__vdso_getcpu_try(void)
|
||||
{
|
||||
int res;
|
||||
|
||||
switch (kern_cpu_selector) {
|
||||
case LINUX_VDSO_CPU_RDTSCP:
|
||||
res = __vdso_getcpu_rdtscp();
|
||||
break;
|
||||
case LINUX_VDSO_CPU_RDPID:
|
||||
res = __vdso_getcpu_rdpid();
|
||||
break;
|
||||
default:
|
||||
res = -1;
|
||||
}
|
||||
return (res);
|
||||
}
|
@ -1,6 +1,6 @@
|
||||
/*-
|
||||
* Copyright (c) 2012 Konstantin Belousov <kib@FreeBSD.org>
|
||||
* Copyright (c) 2016, 2017, 2019 The FreeBSD Foundation
|
||||
* Copyright (c) 2016, 2017, 2019, 2021 The FreeBSD Foundation
|
||||
* Copyright (c) 2021 Dmitry Chagin <dchagin@FreeBSD.org>
|
||||
*
|
||||
* Portions of this software were developed by Konstantin Belousov
|
||||
@ -36,6 +36,8 @@ __FBSDID("$FreeBSD$");
|
||||
#include <x86/x86_var.h>
|
||||
#include <x86/specialreg.h>
|
||||
|
||||
#include <machine/cpufunc.h>
|
||||
|
||||
#include <x86/linux/linux_x86.h>
|
||||
|
||||
int
|
||||
@ -55,3 +57,25 @@ linux_vdso_tsc_selector_idx()
|
||||
return (2);
|
||||
return (amd_cpu ? 1 : 0);
|
||||
}
|
||||
|
||||
int
|
||||
linux_vdso_cpu_selector_idx()
|
||||
{
|
||||
u_int amd_feature, cpu_exthigh, p[4];
|
||||
|
||||
if ((cpu_stdext_feature2 & CPUID_STDEXT2_RDPID) != 0)
|
||||
return (LINUX_VDSO_CPU_RDPID);
|
||||
|
||||
amd_feature = 0;
|
||||
if (cpu_feature != 0) {
|
||||
do_cpuid(0x80000000, p);
|
||||
cpu_exthigh = p[0];
|
||||
if (cpu_exthigh >= 0x80000001) {
|
||||
do_cpuid(0x80000001, p);
|
||||
amd_feature = p[3];
|
||||
}
|
||||
}
|
||||
|
||||
return ((amd_feature & AMDID_RDTSCP) == 0 ?
|
||||
LINUX_VDSO_CPU_DEFAULT : LINUX_VDSO_CPU_RDTSCP);
|
||||
}
|
@ -28,6 +28,11 @@
|
||||
#ifndef _X86_INCLUDE_LINUX_LINUX_X86_H_
|
||||
#define _X86_INCLUDE_LINUX_LINUX_X86_H_
|
||||
|
||||
#define LINUX_VDSO_CPU_DEFAULT 0
|
||||
#define LINUX_VDSO_CPU_RDPID 1
|
||||
#define LINUX_VDSO_CPU_RDTSCP 2
|
||||
|
||||
int linux_vdso_tsc_selector_idx(void);
|
||||
int linux_vdso_cpu_selector_idx(void);
|
||||
|
||||
#endif /* _X86_INCLUDE_LINUX_LINUX_X86_H_ */
|
||||
|
Loading…
Reference in New Issue
Block a user