1/*
2 * Copyright 2023, J��r��me Duval, jerome.duval@gmail.com. All rights reserved.
3 * Distributed under the terms of the MIT License.
4 */
5
6
7#include <sched.h>
8
9#include <syscalls.h>
10
11#ifdef __x86_64__
12
13#include <pthread.h>
14
15#include <x86intrin.h>
16
17#define IA32_FEATURE_RDPID			(1 << 22) // RDPID Instruction
18#define IA32_FEATURE_AMD_EXT_RDTSCP		(1 << 27) // rdtscp instruction
19
20
21typedef int (*sched_cpu_func)();
22static pthread_once_t sSchedCpuInitOnce = PTHREAD_ONCE_INIT;
23static sched_cpu_func sSchedCpuFunc = NULL;
24
25
26static int
27__sched_cpu_syscall()
28{
29	return _kern_get_cpu();
30}
31
32
33static int
34__sched_cpu_rdtscp()
35{
36	uint32_t aux;
37	__rdtscp(&aux);
38	return aux;
39}
40
41
42static int
43__sched_cpu_rdpid()
44{
45	return _rdpid_u32();
46}
47
48
49static void
50initSchedCpuFunc()
51{
52	cpuid_info cpuInfo;
53	get_cpuid(&cpuInfo, 0, 0);
54	if (cpuInfo.eax_0.max_eax >= 0x7) {
55		get_cpuid(&cpuInfo, 0x7, 0);
56		if ((cpuInfo.regs.ecx & IA32_FEATURE_RDPID) != 0) {
57			sSchedCpuFunc = __sched_cpu_rdpid;
58			return;
59		}
60	}
61	get_cpuid(&cpuInfo, 0x80000000, 0);
62	if (cpuInfo.eax_0.max_eax >= 0x80000001) {
63		get_cpuid(&cpuInfo, 0x80000001, 0);
64		if ((cpuInfo.regs.edx & IA32_FEATURE_AMD_EXT_RDTSCP)!= 0) {
65			sSchedCpuFunc = __sched_cpu_rdtscp;
66			return;
67		}
68	}
69	sSchedCpuFunc = __sched_cpu_syscall;
70}
71
72
73int
74sched_getcpu()
75{
76	if (sSchedCpuFunc == NULL) {
77		pthread_once(&sSchedCpuInitOnce, &initSchedCpuFunc);
78	}
79	return sSchedCpuFunc();
80}
81
82
83#else
84int
85sched_getcpu()
86{
87	return _kern_get_cpu();
88}
89#endif
90
91