this repo has no description
1#include "commpage.h"
2#include <sys/mman.h>
3#include <stdio.h>
4#include <errno.h>
5#include <tgmath.h>
6#include <string.h>
7#include <stdlib.h>
8#include <cpuid.h>
9#include <unistd.h>
10#include <sys/sysinfo.h>
11
12// Include commpage definitions
13#define PRIVATE
14#include <i386/cpu_capabilities.h>
15
16static const char* SIGNATURE32 = "commpage 32-bit";
17static const char* SIGNATURE64 = "commpage 64-bit";
18
19static uint64_t get_cpu_caps(void);
20
21#define CGET(p) (commpage + ((p)-_COMM_PAGE_START_ADDRESS))
22
23void commpage_setup(bool _64bit)
24{
25 uint8_t* commpage;
26 uint64_t* cpu_caps64;
27 uint32_t* cpu_caps;
28 uint16_t* version;
29 char* signature;
30 uint64_t my_caps;
31 uint8_t *ncpus, *nactivecpus;
32 uint8_t *physcpus, *logcpus;
33 uint8_t *user_page_shift, *kernel_page_shift;
34 struct sysinfo si;
35
36 commpage = (uint8_t*) mmap((void*)(_64bit ? _COMM_PAGE64_BASE_ADDRESS : _COMM_PAGE32_BASE_ADDRESS),
37 _64bit ? _COMM_PAGE64_AREA_LENGTH : _COMM_PAGE32_AREA_LENGTH, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS, -1, 0);
38 if (commpage == MAP_FAILED)
39 {
40 fprintf(stderr, "Cannot mmap commpage: %s\n", strerror(errno));
41 exit(1);
42 }
43
44 signature = (char*)CGET(_COMM_PAGE_SIGNATURE);
45 version = (uint16_t*)CGET(_COMM_PAGE_VERSION);
46 cpu_caps64 = (uint64_t*)CGET(_COMM_PAGE_CPU_CAPABILITIES64);
47 cpu_caps = (uint32_t*)CGET(_COMM_PAGE_CPU_CAPABILITIES);
48
49 strcpy(signature, _64bit ? SIGNATURE64 : SIGNATURE32);
50 *version = _COMM_PAGE_THIS_VERSION;
51
52 ncpus = (uint8_t*)CGET(_COMM_PAGE_NCPUS);
53 *ncpus = sysconf(_SC_NPROCESSORS_CONF);
54
55 nactivecpus = (uint8_t*)CGET(_COMM_PAGE_ACTIVE_CPUS);
56 *nactivecpus = sysconf(_SC_NPROCESSORS_ONLN);
57
58 // Better imprecise information than no information
59 physcpus = (uint8_t*)CGET(_COMM_PAGE_PHYSICAL_CPUS);
60 logcpus = (uint8_t*)CGET(_COMM_PAGE_LOGICAL_CPUS);
61 *physcpus = *logcpus = *ncpus;
62
63 // I'm not sure if Linux has separate page sizes for kernel and user space.
64 // Apple's code uses left shift logical (1 << user_page_shift) to get the page size value.
65 // Since it's very unlikely that the page size won't be a power of 2, we can use __builtin_ctzl()
66 // as a substitute for log2().
67 user_page_shift = (uint8_t*)CGET(_64bit ? _COMM_PAGE_USER_PAGE_SHIFT_64 : _COMM_PAGE_USER_PAGE_SHIFT_32);
68 kernel_page_shift = (uint8_t*)CGET(_COMM_PAGE_KERNEL_PAGE_SHIFT);
69 *kernel_page_shift = *user_page_shift = (uint8_t)__builtin_ctzl(sysconf(_SC_PAGESIZE));
70
71 my_caps = get_cpu_caps();
72 if (*ncpus == 1)
73 my_caps |= kUP;
74
75 *cpu_caps = (uint32_t) my_caps;
76 *cpu_caps64 = my_caps;
77
78 if (sysinfo(&si) == 0)
79 {
80 uint64_t* memsize = (uint64_t*)CGET(_COMM_PAGE_MEMORY_SIZE);
81 *memsize = si.totalram * si.mem_unit;
82 }
83}
84
85uint64_t get_cpu_caps(void)
86{
87 uint64_t caps = 0;
88
89 {
90 union cpu_flags1 eax;
91 union cpu_flags2 ecx;
92 union cpu_flags3 edx;
93 uint32_t ebx;
94
95 eax.reg = ecx.reg = edx.reg = 0;
96 __cpuid(1, eax.reg, ebx, ecx.reg, edx.reg);
97
98 if (ecx.mmx)
99 caps |= kHasMMX;
100 if (ecx.sse)
101 caps |= kHasSSE;
102 if (ecx.sse2)
103 caps |= kHasSSE2;
104 if (edx.sse3)
105 caps |= kHasSSE3;
106 if (ecx.ia64)
107 caps |= k64Bit;
108 if (edx.ssse3)
109 caps |= kHasSupplementalSSE3;
110 if (edx.sse41)
111 caps |= kHasSSE4_1;
112 if (edx.sse42)
113 caps |= kHasSSE4_2;
114 if (edx.aes)
115 caps |= kHasAES;
116 if (edx.avx)
117 caps |= kHasAVX1_0;
118 if (edx.rdrnd)
119 caps |= kHasRDRAND;
120 if (edx.fma)
121 caps |= kHasFMA;
122 if (edx.f16c)
123 caps |= kHasF16C;
124 }
125 {
126 union cpu_flags4 ebx;
127 union cpu_flags5 ecx;
128 uint32_t edx = 0, eax = 7;
129
130 __cpuid(7, eax, ebx.reg, ecx.reg, edx);
131
132 if (ebx.erms)
133 caps |= kHasENFSTRG;
134 if (ebx.avx2)
135 caps |= kHasAVX2_0;
136 if (ebx.bmi1)
137 caps |= kHasBMI1;
138 if (ebx.bmi2)
139 caps |= kHasBMI2;
140 if (ebx.rtm)
141 caps |= kHasRTM;
142 if (ebx.hle)
143 caps |= kHasHLE;
144 if (ebx.rdseed)
145 caps |= kHasRDSEED;
146 if (ebx.adx)
147 caps |= kHasADX;
148 if (ebx.mpx)
149 caps |= kHasMPX;
150 if (ebx.sgx)
151 caps |= kHasSGX;
152 }
153
154 return caps;
155}
156
157unsigned long commpage_address(bool _64bit)
158{
159 return _64bit ? _COMM_PAGE64_BASE_ADDRESS : _COMM_PAGE32_BASE_ADDRESS;
160}
161