1/* $NetBSD: procfs_machdep.c,v 1.13 2016/08/08 09:39:06 msaitoh Exp $ */
2
3/*
4 * Copyright (c) 2001 Wasabi Systems, Inc.
5 * All rights reserved.
6 *
7 * Written by Frank van der Linden and Jason R. Thorpe for
8 * Wasabi Systems, Inc.
9 *
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
12 * are met:
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
18 * 3. All advertising materials mentioning features or use of this software
19 * must display the following acknowledgement:
20 * This product includes software developed for the NetBSD Project by
21 * Wasabi Systems, Inc.
22 * 4. The name of Wasabi Systems, Inc. may not be used to endorse
23 * or promote products derived from this software without specific prior
24 * written permission.
25 *
26 * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND
27 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
28 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
29 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC
30 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
31 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
32 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
33 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
34 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
35 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
36 * POSSIBILITY OF SUCH DAMAGE.
37 */
38
39/*
40 * NOTE: We simply use the primary CPU's cpuid_level and tsc_freq
41 * here. Might want to change this later.
42 */
43
44#include <sys/cdefs.h>
45__KERNEL_RCSID(0, "$NetBSD: procfs_machdep.c,v 1.13 2016/08/08 09:39:06 msaitoh Exp $");
46
47#include <sys/param.h>
48#include <sys/systm.h>
49#include <sys/mount.h>
50#include <sys/stat.h>
51#include <sys/vnode.h>
52
53#include <miscfs/procfs/procfs.h>
54
55#include <machine/cpu.h>
56#include <machine/reg.h>
57#include <machine/specialreg.h>
58
59/*
60 * The feature table. The order is the same as Linux's
61 * x86/include/asm/cpufeatures.h.
62 */
63static const char * const x86_features[][32] = {
64 { /* (0) Common: 0x0000001 edx */
65 "fpu", "vme", "de", "pse", "tsc", "msr", "pae", "mce",
66 "cx8", "apic", NULL, "sep", "mtrr", "pge", "mca", "cmov",
67 "pat", "pse36", "pn", "clflush", NULL, "dts", "acpi", "mmx",
68 "fxsr", "sse", "sse2", "ss", "ht", "tm", "ia64", "pbe"},
69
70 { /* (1) AMD-defined: 0x80000001 edx */
71 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
72 NULL, NULL, NULL, "syscall", NULL, NULL, NULL, NULL,
73 NULL, NULL, NULL, "mp", "nx", NULL, "mmxext", NULL,
74 NULL, "fxsr_opt", "pdpe1gb", "rdtscp", NULL, "lm", "3dnowext","3dnow"},
75
76 { /* (2) Transmeta-defined */
77 "recovery", "longrun", NULL, "lrti", NULL, NULL, NULL, NULL,
78 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
79 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
80 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
81
82 { /* (3) Linux mapping */
83 "cxmmx", NULL, "cyrix_arr", "centaur_mcr", NULL,
84 "constant_tsc", NULL, NULL,
85 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
86 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
87 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
88
89 { /* (4) Intel-defined: 0x00000001 ecx */
90 "pni", "pclmulqdq", "dtes64", "monitor", "ds_cpl", "vmx", "smx", "est",
91 "tm2", "ssse3", "cid", "sdbg", "fma", "cx16", "xtpr", "pdcm",
92 NULL, "pcid", "dca", "sse4_1", "sse4_2", "x2apic", "movbe", "popcnt",
93 "tsc_deadline_timer", "aes", "xsave", NULL,
94 "avx", "f16c", "rdrand", "hypervisor"},
95
96 { /* (5) VIA/Cyrix/Centaur-defined */
97 NULL, NULL, "rng", "rng_en", NULL, NULL, "ace", "ace_en",
98 "ace2", "ace2_en", "phe", "phe_en", "pmm", "pmm_en", NULL, NULL,
99 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
100 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
101
102 { /* (6) AMD defined 80000001 ecx */
103 "lahf_lm", "cmp_legacy", "svm", "extapic",
104 "cr8_legacy", "abm", "sse4a", "misalignsse",
105 "3dnowprefetch", "osvw", "ibs", "xop", "skinit", "wdt", NULL, "lwp",
106 "fma4", "tce", NULL, "nodeid_msr",
107 NULL, "tbm", "topoext", "perfctr_core",
108 "perfctr_nb", NULL, "bpext", "ptsc",
109 "perfctr_l2", "mwaitx", NULL, NULL},
110
111 { /* (7) Linux mapping */
112 NULL, NULL, "cpb", "ebp", NULL, "pln", "pts", "dtherm",
113 "hw_pstate", "proc_feedback", NULL, NULL,
114 NULL, NULL, NULL, "intel_pt",
115 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
116 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
117
118 { /* (8) Linux mapping */
119 "tpr_shadow", "vnmi", "flexpriority", "ept",
120 "vpid", "npt", "lbrv", "svm_lock",
121 "nrip_save", "tsc_scale", "vmcb_clean", "flushbyasid",
122 "decodeassists", "pausefilter", "pfthreshold", "vmmcall",
123 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
124 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
125
126 { /* (9) Intel-defined: 00000007 ebx */
127 "fsgsbase", "tsc_adjust", NULL, "bmi1", "hle", "avx2", NULL, "smep",
128 "bmi2", "erms", "invpcid", "rtm", "cqm", NULL, "mpx", NULL,
129 "avx512f", "avx512dq", "rdseed", "adx",
130 "smap", NULL, "pcommit", "clflushopt",
131 "clwb", NULL, "avx512pf", "avx512er",
132 "avx512cd", "sha_ni", "avx512bw", "avx512vl"},
133
134 { /* (10) 0000000d eax */
135 "xsaveopt", "xsavec", "xgetbv1", "xsaves", NULL, NULL, NULL, NULL,
136 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
137 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
138 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
139
140 { /* (11) 0x0000000f:0 edx */
141 NULL, "cqm_llc", NULL, NULL, NULL, NULL, NULL, NULL,
142 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
143 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
144 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
145
146 { /* (12) 0x0000000f:1 edx */
147 "cqm_occup_llc", NULL, NULL, NULL, NULL, NULL, NULL, NULL,
148 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
149 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL,
150 NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL},
151};
152
153static int procfs_getonecpu(int, struct cpu_info *, char *, size_t *);
154
155/*
156 * Linux-style /proc/cpuinfo.
157 * Only used when procfs is mounted with -o linux.
158 *
159 * In the multiprocessor case, this should be a loop over all CPUs.
160 */
161int
162procfs_getcpuinfstr(char *bf, size_t *len)
163{
164 struct cpu_info *ci;
165 CPU_INFO_ITERATOR cii;
166 size_t i, total, size, used;
167
168 i = total = 0;
169 used = size = *len;
170
171 for (CPU_INFO_FOREACH(cii, ci)) {
172 procfs_getonecpu(i++, ci, bf, &used);
173 total += used + 1;
174 if (used + 1 < size) {
175 bf += used;
176 *bf++ = '\n';
177 size -= used + 1;
178 used = size;
179 } else
180 used = 0;
181 }
182 size = *len;
183 *len = total;
184 return size < *len ? -1 : 0;
185}
186
187static int
188procfs_getonefeatreg(uint32_t reg, const char * const *table, char *p,
189 size_t *left)
190{
191 size_t l;
192
193 for (size_t i = 0; i < 32; i++) {
194 if ((reg & (1 << i)) && table[i]) {
195 l = snprintf(p, *left, "%s ", table[i]);
196 if (l < *left) {
197 *left -= l;
198 p += l;
199 } else
200 break;
201 }
202 }
203
204 return 0; /* XXX */
205}
206
207/*
208 * Print feature bits. The code assume that unused entry of x86_features[]
209 * is zero-cleared.
210 *
211 * XXX This function will be rewritten when all of linux entries are
212 * decoded.
213 */
214static int
215procfs_getonecpufeatures(struct cpu_info *ci, char *p, size_t *left)
216{
217 size_t last = *left;
218 size_t diff;
219
220 procfs_getonefeatreg(ci->ci_feat_val[0], x86_features[0], p, left);
221 diff = last - *left;
222
223 procfs_getonefeatreg(ci->ci_feat_val[2], x86_features[1], p + diff,
224 left);
225 diff = last - *left;
226
227 /* x86_features[2] is for Transmeta */
228 /* x86_features[3] is Linux defined mapping */
229
230 procfs_getonefeatreg(ci->ci_feat_val[1], x86_features[4], p + diff,
231 left);
232 diff = last - *left;
233
234 procfs_getonefeatreg(ci->ci_feat_val[4], x86_features[5], p + diff,
235 left);
236 diff = last - *left;
237
238 procfs_getonefeatreg(ci->ci_feat_val[3], x86_features[6], p + diff,
239 left);
240 diff = last - *left;
241
242 /* x86_features[7] is Linux defined mapping */
243 /* x86_features[8] is Linux defined mapping */
244
245 procfs_getonefeatreg(ci->ci_feat_val[5], x86_features[9], p + diff,
246 left);
247 diff = last - *left;
248
249 /* (10) 0000000d eax */
250 /* (11) 0x0000000f(ecx=0) edx */
251 /* (12) 0x0000000f(ecx=1) edx */
252
253 return 0; /* XXX */
254}
255
256static int
257procfs_getonecpu(int xcpu, struct cpu_info *ci, char *bf, size_t *len)
258{
259 size_t left, l, size;
260 char featurebuf[1024], *p;
261
262 p = featurebuf;
263 left = sizeof(featurebuf);
264 size = *len;
265 procfs_getonecpufeatures(ci, p, &left);
266
267 p = bf;
268 left = *len;
269 size = 0;
270 l = snprintf(p, left,
271 "processor\t: %d\n"
272 "vendor_id\t: %s\n"
273 "cpu family\t: %d\n"
274 "model\t\t: %d\n"
275 "model name\t: %s\n"
276 "stepping\t: ",
277 xcpu,
278 (char *)ci->ci_vendor,
279 CPUID_TO_FAMILY(ci->ci_signature),
280 CPUID_TO_MODEL(ci->ci_signature),
281 cpu_brand_string
282 );
283 size += l;
284 if (l < left) {
285 left -= l;
286 p += l;
287 } else
288 left = 0;
289
290 if (cpuid_level >= 0)
291 l = snprintf(p, left, "%d\n",
292 CPUID_TO_STEPPING(ci->ci_signature));
293 else
294 l = snprintf(p, left, "unknown\n");
295
296 size += l;
297 if (l < left) {
298 left -= l;
299 p += l;
300 } else
301 left = 0;
302
303 if (ci->ci_data.cpu_cc_freq != 0) {
304 uint64_t freq, fraq;
305
306 freq = (ci->ci_data.cpu_cc_freq + 4999) / 1000000;
307 fraq = ((ci->ci_data.cpu_cc_freq + 4999) / 10000) % 100;
308 l = snprintf(p, left, "cpu MHz\t\t: %" PRIu64 ".%02" PRIu64
309 "\n", freq, fraq);
310 } else
311 l = snprintf(p, left, "cpu MHz\t\t: unknown\n");
312
313 size += l;
314 if (l < left) {
315 left -= l;
316 p += l;
317 } else
318 left = 0;
319
320 l = snprintf(p, left,
321 "fdiv_bug\t: %s\n"
322 "fpu\t\t: %s\n"
323 "fpu_exception\t: yes\n"
324 "cpuid level\t: %d\n"
325 "wp\t\t: %s\n"
326 "flags\t\t: %s\n",
327 i386_fpu_fdivbug ? "yes" : "no", /* an old pentium */
328 i386_fpu_present ? "yes" : "no", /* not a 486SX */
329 cpuid_level,
330 (rcr0() & CR0_WP) ? "yes" : "no",
331 featurebuf
332 );
333 size += l;
334
335 left = *len;
336 *len = size;
337 return left < *len ? -1 : 0;
338}
339
340#if defined(__HAVE_PROCFS_MACHDEP) && !defined(__x86_64__)
341
342void
343procfs_machdep_allocvp(struct vnode *vp)
344{
345 struct pfsnode *pfs = vp->v_data;
346
347 switch (pfs->pfs_type) {
348 case Pmachdep_xmmregs:
349 /* /proc/N/xmmregs = -rw------- */
350 pfs->pfs_mode = S_IRUSR|S_IWUSR;
351 vp->v_type = VREG;
352 break;
353 default:
354 KASSERT(false);
355 }
356}
357
358int
359procfs_machdep_rw(struct lwp *curl, struct lwp *l, struct pfsnode *pfs,
360 struct uio *uio)
361{
362
363 switch (pfs->pfs_type) {
364 case Pmachdep_xmmregs:
365 return (procfs_machdep_doxmmregs(curl, l, pfs, uio));
366 default:
367 KASSERT(false);
368 }
369 return EINVAL;
370}
371
372int
373procfs_machdep_getattr(struct vnode *vp, struct vattr *vap, struct proc *procp)
374{
375 struct pfsnode *pfs = VTOPFS(vp);
376
377 switch (pfs->pfs_type) {
378 case Pmachdep_xmmregs:
379 vap->va_bytes = vap->va_size = sizeof(struct xmmregs);
380 break;
381 default:
382 KASSERT(false);
383 }
384 return 0;
385}
386
387int
388procfs_machdep_doxmmregs(struct lwp *curl, struct lwp *l,
389 struct pfsnode *pfs, struct uio *uio)
390{
391
392 return process_machdep_doxmmregs(curl, l, uio);
393}
394
395int
396procfs_machdep_validxmmregs(struct lwp *l, struct mount *mp)
397{
398
399 return process_machdep_validxmmregs(l->l_proc);
400}
401
402#endif
403