Cygwin: pinfo: use stpcpy where appropriate
[newlib-cygwin.git] / winsup / cygwin / fhandler / proc.cc
blobbe107cb8eaccbe5ccf8aff83b89350cdc8af48bc
1 /* fhandler_proc.cc: fhandler for /proc virtual filesystem
3 This file is part of Cygwin.
5 This software is a copyrighted work licensed under the terms of the
6 Cygwin license. Please consult the file "CYGWIN_LICENSE" for
7 details. */
9 #include "winsup.h"
10 #include "miscfuncs.h"
11 #include <unistd.h>
12 #include <stdlib.h>
13 #include <stdio.h>
14 #include <langinfo.h>
15 #include "cygerrno.h"
16 #include "security.h"
17 #include "path.h"
18 #include "shared_info.h"
19 #include "fhandler.h"
20 #include "fhandler_virtual.h"
21 #include "pinfo.h"
22 #include "dtable.h"
23 #include "cygheap.h"
24 #include "tls_pbuf.h"
25 #include <sys/utsname.h>
26 #include <sys/param.h>
27 #include <sys/sysinfo.h>
28 #include "ntdll.h"
29 #include <winioctl.h>
30 #include <wchar.h>
31 #include <wctype.h>
32 #include "cpuid.h"
33 #include "mount.h"
34 #include <math.h>
36 #define _LIBC
37 #include <dirent.h>
39 static off_t format_proc_loadavg (void *, char *&);
40 static off_t format_proc_meminfo (void *, char *&);
41 static off_t format_proc_stat (void *, char *&);
42 static off_t format_proc_version (void *, char *&);
43 static off_t format_proc_uptime (void *, char *&);
44 static off_t format_proc_cpuinfo (void *, char *&);
45 static off_t format_proc_partitions (void *, char *&);
46 static off_t format_proc_self (void *, char *&);
47 static off_t format_proc_cygdrive (void *, char *&);
48 static off_t format_proc_mounts (void *, char *&);
49 static off_t format_proc_filesystems (void *, char *&);
50 static off_t format_proc_swaps (void *, char *&);
51 static off_t format_proc_devices (void *, char *&);
52 static off_t format_proc_misc (void *, char *&);
53 static off_t format_proc_locales (void *, char *&);
54 static off_t format_proc_codesets (void *, char *&);
56 /* names of objects in /proc */
57 static const virt_tab_t proc_tab[] = {
58 { _VN ("."), FH_PROC, virt_directory, NULL },
59 { _VN (".."), FH_PROC, virt_directory, NULL },
60 { _VN ("codesets"), FH_PROC, virt_file, format_proc_codesets },
61 { _VN ("cpuinfo"), FH_PROC, virt_file, format_proc_cpuinfo },
62 { _VN ("cygdrive"), FH_PROC, virt_symlink, format_proc_cygdrive },
63 { _VN ("devices"), FH_PROC, virt_file, format_proc_devices },
64 { _VN ("filesystems"), FH_PROC, virt_file, format_proc_filesystems },
65 { _VN ("loadavg"), FH_PROC, virt_file, format_proc_loadavg },
66 { _VN ("locales"), FH_PROC, virt_file, format_proc_locales },
67 { _VN ("meminfo"), FH_PROC, virt_file, format_proc_meminfo },
68 { _VN ("misc"), FH_PROC, virt_file, format_proc_misc },
69 { _VN ("mounts"), FH_PROC, virt_symlink, format_proc_mounts },
70 { _VN ("net"), FH_PROCNET, virt_directory, NULL },
71 { _VN ("partitions"), FH_PROC, virt_file, format_proc_partitions },
72 { _VN ("registry"), FH_REGISTRY, virt_directory, NULL },
73 { _VN ("registry32"), FH_REGISTRY, virt_directory, NULL },
74 { _VN ("registry64"), FH_REGISTRY, virt_directory, NULL },
75 { _VN ("self"), FH_PROC, virt_symlink, format_proc_self },
76 { _VN ("stat"), FH_PROC, virt_file, format_proc_stat },
77 { _VN ("swaps"), FH_PROC, virt_file, format_proc_swaps },
78 { _VN ("sys"), FH_PROCSYS, virt_directory, NULL },
79 { _VN ("sysvipc"), FH_PROCSYSVIPC, virt_directory, NULL },
80 { _VN ("uptime"), FH_PROC, virt_file, format_proc_uptime },
81 { _VN ("version"), FH_PROC, virt_file, format_proc_version },
82 { NULL, 0, FH_NADA, virt_none, NULL }
85 #define PROC_DIR_COUNT 4
87 static const int PROC_LINK_COUNT = (sizeof (proc_tab) / sizeof (virt_tab_t)) - 1;
89 /* name of the /proc filesystem */
90 const char proc[] = "/proc";
91 const size_t proc_len = sizeof (proc) - 1;
93 /* bsearch compare function. */
94 static int
95 proc_tab_cmp (const void *key, const void *memb)
97 int ret = strncmp (((virt_tab_t *) key)->name, ((virt_tab_t *) memb)->name,
98 ((virt_tab_t *) memb)->name_len);
99 if (!ret && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '\0' && ((virt_tab_t *) key)->name[((virt_tab_t *) memb)->name_len] != '/')
100 return 1;
101 return ret;
104 /* Helper function to perform a binary search of the incoming pathname
105 against the alpha-sorted virtual file table. */
106 virt_tab_t *
107 virt_tab_search (const char *path, bool prefix, const virt_tab_t *table,
108 size_t nelem)
110 virt_tab_t key = { path, 0, FH_NADA, virt_none, NULL };
111 virt_tab_t *entry = (virt_tab_t *) bsearch (&key, table, nelem,
112 sizeof (virt_tab_t),
113 proc_tab_cmp);
114 if (entry && (path[entry->name_len] == '\0'
115 || (prefix && path[entry->name_len] == '/')))
116 return entry;
117 return NULL;
120 /* Auxillary function that returns the fhandler associated with the given
121 path. */
122 fh_devices
123 fhandler_proc::get_proc_fhandler (const char *path)
125 debug_printf ("get_proc_fhandler(%s)", path);
126 path += proc_len;
127 /* Since this method is called from path_conv::check we can't rely on
128 it being normalised and therefore the path may have runs of slashes
129 in it. */
130 while (isdirsep (*path))
131 path++;
133 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
134 if (*path == 0)
135 return FH_PROC;
137 virt_tab_t *entry = virt_tab_search (path, true, proc_tab,
138 PROC_LINK_COUNT);
139 if (entry)
140 return entry->fhandler;
142 char *e;
143 pid_t pid = strtoul (path, &e, 10);
144 if (*e != '/' && *e != '\0')
145 return FH_NADA;
146 pinfo p (pid);
147 /* If p->pid != pid, then pid is actually the Windows PID for an execed
148 Cygwin process, and the pinfo entry is the additional entry created
149 at exec time. We don't want to enable the user to access a process
150 entry by using the Win32 PID, though. */
151 if (p && p->pid == pid)
153 /* Check for entry in fd subdir */
154 if (!strncmp (++e, "fd/", 3) && e[3] != '\0')
155 return FH_PROCESSFD;
156 return FH_PROCESS;
159 bool has_subdir = false;
160 while (*path)
161 if (isdirsep (*path++))
163 has_subdir = true;
164 break;
167 if (has_subdir)
168 /* The user is trying to access a non-existent subdirectory of /proc. */
169 return FH_NADA;
170 else
171 /* Return FH_PROC so that we can return EROFS if the user is trying to
172 create a file. */
173 return FH_PROC;
176 virtual_ftype_t
177 fhandler_proc::exists ()
179 const char *path = get_name ();
180 debug_printf ("exists (%s)", path);
181 path += proc_len;
182 if (*path == 0)
183 return virt_rootdir;
184 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
185 PROC_LINK_COUNT);
186 if (entry)
188 fileid = entry - proc_tab;
189 return entry->type;
191 return virt_none;
194 fhandler_proc::fhandler_proc ():
195 fhandler_virtual ()
200 fhandler_proc::fstat (struct stat *buf)
202 const char *path = get_name ();
203 debug_printf ("fstat (%s)", path);
205 path += proc_len;
206 fhandler_base::fstat (buf);
208 buf->st_mode &= ~_IFMT & NO_W;
210 if (!*path)
212 winpids pids ((DWORD) 0);
213 buf->st_ino = 2;
214 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
215 buf->st_nlink = PROC_DIR_COUNT + 2 + pids.npids;
216 return 0;
218 else
220 virt_tab_t *entry = virt_tab_search (path + 1, false, proc_tab,
221 PROC_LINK_COUNT);
222 if (entry)
224 if (entry->type == virt_directory)
225 buf->st_mode |= S_IFDIR | S_IXUSR | S_IXGRP | S_IXOTH;
226 else if (entry->type == virt_symlink)
227 buf->st_mode = S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO;
228 else
230 buf->st_mode &= NO_X;
231 buf->st_mode |= S_IFREG;
233 return 0;
236 set_errno (ENOENT);
237 return -1;
240 DIR *
241 fhandler_proc::opendir (int fd)
243 DIR *dir = fhandler_virtual::opendir (fd);
244 if (dir && !(dir->__handle = (void *) new winpids ((DWORD) 0)))
246 free (dir);
247 dir = NULL;
248 set_errno (ENOMEM);
250 return dir;
254 fhandler_proc::closedir (DIR *dir)
256 delete (winpids *) dir->__handle;
257 return fhandler_virtual::closedir (dir);
261 fhandler_proc::readdir (DIR *dir, dirent *de)
263 int res;
264 if (dir->__d_position < PROC_LINK_COUNT)
266 strcpy (de->d_name, proc_tab[dir->__d_position].name);
267 de->d_type = virt_ftype_to_dtype (proc_tab[dir->__d_position].type);
268 dir->__d_position++;
269 dir->__flags |= dirent_saw_dot | dirent_saw_dot_dot;
270 res = 0;
272 else
274 winpids &pids = *(winpids *) dir->__handle;
275 int found = 0;
276 res = ENMFILE;
277 for (unsigned i = 0; i < pids.npids; i++)
278 if (found++ == dir->__d_position - PROC_LINK_COUNT)
280 __small_sprintf (de->d_name, "%d", pids[i]->pid);
281 de->d_type = DT_DIR;
282 dir->__d_position++;
283 res = 0;
284 break;
288 syscall_printf ("%d = readdir(%p, %p) (%s)", res, dir, de, de->d_name);
289 return res;
293 fhandler_proc::open (int flags, mode_t mode)
295 int proc_file_no = -1;
297 int res = fhandler_virtual::open (flags, mode);
298 if (!res)
299 goto out;
301 nohandle (true);
303 const char *path;
305 path = get_name () + proc_len;
307 if (!*path)
309 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
311 set_errno (EEXIST);
312 res = 0;
313 goto out;
315 else if (flags & O_WRONLY)
317 set_errno (EISDIR);
318 res = 0;
319 goto out;
321 else
323 diropen = true;
324 goto success;
328 proc_file_no = -1;
329 for (int i = 0; proc_tab[i].name; i++)
330 if (path_prefix_p (proc_tab[i].name, path + 1, strlen (proc_tab[i].name),
331 false))
333 proc_file_no = i;
334 if (proc_tab[i].fhandler != FH_PROC)
336 if ((flags & (O_CREAT | O_EXCL)) == (O_CREAT | O_EXCL))
338 set_errno (EEXIST);
339 res = 0;
340 goto out;
342 else if (flags & O_WRONLY)
344 set_errno (EISDIR);
345 res = 0;
346 goto out;
348 else
350 diropen = true;
351 goto success;
356 if (proc_file_no == -1)
358 if (flags & O_CREAT)
360 set_errno (EROFS);
361 res = 0;
362 goto out;
364 else
366 set_errno (ENOENT);
367 res = 0;
368 goto out;
371 if (flags & O_WRONLY)
373 set_errno (EROFS);
374 res = 0;
375 goto out;
378 fileid = proc_file_no;
379 if (!fill_filebuf ())
381 res = 0;
382 goto out;
385 if (flags & O_APPEND)
386 position = filesize;
387 else
388 position = 0;
390 success:
391 res = 1;
392 set_flags ((flags & ~O_TEXT) | O_BINARY);
393 set_open_status ();
394 out:
395 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res, flags, mode);
396 return res;
399 bool
400 fhandler_proc::fill_filebuf ()
402 if (fileid < PROC_LINK_COUNT && proc_tab[fileid].format_func)
404 filesize = proc_tab[fileid].format_func (NULL, filebuf);
405 if (filesize > 0)
406 return true;
408 return false;
411 extern "C" int uname_x (struct utsname *);
413 static off_t
414 format_proc_version (void *, char *&destbuf)
416 tmp_pathbuf tp;
417 char *buf = tp.c_get ();
418 char *bufptr = buf;
419 struct utsname uts_name;
421 uname_x (&uts_name);
422 bufptr += __small_sprintf (bufptr, "%s version %s (%s@%s) (%s) %s\n",
423 uts_name.sysname, uts_name.release, USERNAME, HOSTNAME,
424 GCC_VERSION, uts_name.version);
426 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
427 memcpy (destbuf, buf, bufptr - buf);
428 return bufptr - buf;
431 static off_t
432 format_proc_loadavg (void *, char *&destbuf)
434 extern int get_process_state (DWORD dwProcessId);
435 unsigned int running = 0;
436 winpids pids ((DWORD) 0);
438 for (unsigned i = 0; i < pids.npids; i++)
439 switch (get_process_state (i)) {
440 case 'O':
441 case 'R':
442 running++;
443 break;
446 double loadavg[3] = { 0.0, 0.0, 0.0 };
447 getloadavg (loadavg, 3);
449 #define HUNDRETHS(l) (int)((l - floor(l))*100)
451 destbuf = (char *) crealloc_abort (destbuf, 48);
452 return __small_sprintf (destbuf, "%u.%02u %u.%02u %u.%02u %u/%u\n",
453 (int)loadavg[0], HUNDRETHS(loadavg[0]),
454 (int)loadavg[1], HUNDRETHS(loadavg[1]),
455 (int)loadavg[2], HUNDRETHS(loadavg[2]),
456 running, (unsigned int)pids.npids);
459 static off_t
460 format_proc_meminfo (void *, char *&destbuf)
462 unsigned long long mem_total, mem_free, swap_total, swap_free;
463 struct sysinfo info;
465 sysinfo (&info);
466 mem_total = (unsigned long long) info.totalram * info.mem_unit;
467 mem_free = (unsigned long long) info.freeram * info.mem_unit;
468 swap_total = (unsigned long long) info.totalswap * info.mem_unit;
469 swap_free = (unsigned long long) info.freeswap * info.mem_unit;
471 destbuf = (char *) crealloc_abort (destbuf, 512);
472 return sprintf (destbuf, "MemTotal: %10llu kB\n"
473 "MemFree: %10llu kB\n"
474 "HighTotal: 0 kB\n"
475 "HighFree: 0 kB\n"
476 "LowTotal: %10llu kB\n"
477 "LowFree: %10llu kB\n"
478 "SwapTotal: %10llu kB\n"
479 "SwapFree: %10llu kB\n",
480 mem_total >> 10, mem_free >> 10,
481 mem_total >> 10, mem_free >> 10,
482 swap_total >> 10, swap_free >> 10);
485 static off_t
486 format_proc_uptime (void *, char *&destbuf)
488 unsigned long long uptime = 0ULL, idle_time = 0ULL;
489 NTSTATUS status;
490 SYSTEM_TIMEOFDAY_INFORMATION stodi;
491 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
492 appears to contain some trailing additional information from
493 what I can tell after examining the content.
494 FIXME: It would be nice if this could be verified somehow. */
495 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
496 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
497 alloca (sizeof_spi);
499 status = NtQuerySystemInformation (SystemTimeOfDayInformation, &stodi,
500 sizeof stodi, NULL);
501 if (NT_SUCCESS (status))
502 uptime = (stodi.CurrentTime.QuadPart - stodi.BootTime.QuadPart) / 100000ULL;
503 else
504 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
505 "status %y", status);
507 if (NT_SUCCESS (NtQuerySystemInformation (SystemPerformanceInformation,
508 spi, sizeof_spi, NULL)))
509 idle_time = (spi->IdleTime.QuadPart / wincap.cpu_count ())
510 / 100000ULL;
512 destbuf = (char *) crealloc_abort (destbuf, 80);
513 return __small_sprintf (destbuf, "%U.%02u %U.%02u\n",
514 uptime / 100, long (uptime % 100),
515 idle_time / 100, long (idle_time % 100));
518 static off_t
519 format_proc_stat (void *, char *&destbuf)
521 unsigned long pages_in = 0UL, pages_out = 0UL, interrupt_count = 0UL,
522 context_switches = 0UL, swap_in = 0UL, swap_out = 0UL;
523 time_t boot_time = 0;
524 NTSTATUS status;
525 /* Sizeof SYSTEM_PERFORMANCE_INFORMATION on 64 bit systems. It
526 appears to contain some trailing additional information from
527 what I can tell after examining the content.
528 FIXME: It would be nice if this could be verified somehow. */
529 const size_t sizeof_spi = sizeof (SYSTEM_PERFORMANCE_INFORMATION) + 16;
530 PSYSTEM_PERFORMANCE_INFORMATION spi = (PSYSTEM_PERFORMANCE_INFORMATION)
531 alloca (sizeof_spi);
532 SYSTEM_TIMEOFDAY_INFORMATION stodi;
533 tmp_pathbuf tp;
535 char *buf = tp.c_get ();
536 char *eobuf = buf;
538 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt[wincap.cpu_count ()];
539 status = NtQuerySystemInformation (SystemProcessorPerformanceInformation,
540 (PVOID) spt,
541 sizeof spt[0] * wincap.cpu_count (), NULL);
542 if (!NT_SUCCESS (status))
543 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
544 "status %y", status);
545 else
547 unsigned long long user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
548 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
550 kernel_time += (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart)
551 * CLOCKS_PER_SEC / NS100PERSEC;
552 user_time += spt[i].UserTime.QuadPart * CLOCKS_PER_SEC / NS100PERSEC;
553 idle_time += spt[i].IdleTime.QuadPart * CLOCKS_PER_SEC / NS100PERSEC;
556 eobuf += __small_sprintf (eobuf, "cpu %U %U %U %U\n",
557 user_time, 0ULL, kernel_time, idle_time);
558 user_time = 0ULL, kernel_time = 0ULL, idle_time = 0ULL;
559 for (unsigned long i = 0; i < wincap.cpu_count (); i++)
561 interrupt_count += spt[i].InterruptCount;
562 kernel_time = (spt[i].KernelTime.QuadPart - spt[i].IdleTime.QuadPart)
563 * CLOCKS_PER_SEC / NS100PERSEC;
564 user_time = spt[i].UserTime.QuadPart * CLOCKS_PER_SEC / NS100PERSEC;
565 idle_time = spt[i].IdleTime.QuadPart * CLOCKS_PER_SEC / NS100PERSEC;
566 eobuf += __small_sprintf (eobuf, "cpu%d %U %U %U %U\n", i,
567 user_time, 0ULL, kernel_time, idle_time);
570 status = NtQuerySystemInformation (SystemPerformanceInformation,
571 (PVOID) spi, sizeof_spi, NULL);
572 if (!NT_SUCCESS (status))
574 debug_printf ("NtQuerySystemInformation(SystemPerformanceInformation)"
575 ", status %y", status);
576 memset (spi, 0, sizeof_spi);
578 status = NtQuerySystemInformation (SystemTimeOfDayInformation,
579 (PVOID) &stodi, sizeof stodi, NULL);
580 if (!NT_SUCCESS (status))
581 debug_printf ("NtQuerySystemInformation(SystemTimeOfDayInformation), "
582 "status %y", status);
584 if (!NT_SUCCESS (status))
586 __seterrno_from_nt_status (status);
587 return 0;
590 pages_in = spi->PagesRead;
591 pages_out = spi->PagefilePagesWritten + spi->MappedFilePagesWritten;
592 /* Note: there is no distinction made in this structure between pages read
593 from the page file and pages read from mapped files, but there is such
594 a distinction made when it comes to writing. Goodness knows why. The
595 value of swap_in, then, will obviously be wrong but its our best guess. */
596 swap_in = spi->PagesRead;
597 swap_out = spi->PagefilePagesWritten;
598 context_switches = spi->ContextSwitches;
599 boot_time = to_time_t (&stodi.BootTime);
601 eobuf += __small_sprintf (eobuf, "page %u %u\n"
602 "swap %u %u\n"
603 "intr %u\n"
604 "ctxt %u\n"
605 "btime %u\n",
606 pages_in, pages_out,
607 swap_in, swap_out,
608 interrupt_count,
609 context_switches,
610 boot_time);
611 destbuf = (char *) crealloc_abort (destbuf, eobuf - buf);
612 memcpy (destbuf, buf, eobuf - buf);
613 return eobuf - buf;
616 #define print(x) { bufptr = stpcpy (bufptr, (x)); }
617 /* feature test unconditional print */
618 #define ftuprint(msg) print (" " msg)
619 /* feature test bit position (0-32) and conditional print */
620 #define ftcprint(feat,bitno,msg) if ((feat) & (1 << (bitno))) { ftuprint (msg); }
622 static inline uint32_t
623 get_msb (uint32_t in)
625 return 32 - __builtin_clz (in);
628 static inline uint32_t
629 mask_bits (uint32_t in)
631 uint32_t bits = get_msb (in) - 1;
632 if (in & (in - 1))
633 ++bits;
634 return bits;
637 static off_t
638 format_proc_cpuinfo (void *, char *&destbuf)
640 WCHAR cpu_key[128], *cpu_num_p;
641 DWORD orig_affinity_mask = 0;
642 GROUP_AFFINITY orig_group_affinity;
643 int cpu_number;
644 const int BUFSIZE = 256;
645 union
647 BYTE b[BUFSIZE];
648 char s[BUFSIZE];
649 WCHAR w[BUFSIZE / sizeof (WCHAR)];
650 DWORD d;
651 uint32_t m[13];
652 } in_buf;
653 tmp_pathbuf tp;
655 char *buf = tp.c_get ();
656 char *bufptr = buf;
658 WORD num_cpu_per_group = __get_cpus_per_group ();
660 cpu_num_p = wcpcpy (cpu_key, L"\\Registry\\Machine\\HARDWARE\\DESCRIPTION"
661 "\\System\\CentralProcessor\\");
662 for (cpu_number = 0; ; cpu_number++)
664 __small_swprintf (cpu_num_p, L"%d", cpu_number);
665 if (!NT_SUCCESS (RtlCheckRegistryKey (RTL_REGISTRY_ABSOLUTE, cpu_key)))
666 break;
668 WORD cpu_group = cpu_number / num_cpu_per_group;
669 KAFFINITY cpu_mask = 1L << (cpu_number % num_cpu_per_group);
670 GROUP_AFFINITY affinity = {
671 .Mask = cpu_mask,
672 .Group = cpu_group,
675 if (!SetThreadGroupAffinity (GetCurrentThread (), &affinity,
676 &orig_group_affinity))
677 system_printf ("SetThreadGroupAffinity(%x,%d (%x/%d)) failed %E",
678 cpu_mask, cpu_group, cpu_number, cpu_number);
679 orig_affinity_mask = 1; /* Just mark success. */
680 /* I'm not sure whether the thread changes processor immediately
681 and I'm not sure whether this function will cause the thread
682 to be rescheduled */
683 yield ();
685 DWORD cpu_mhz = 0;
686 union
688 LONG uc_len; /* -max size of buffer before call */
689 char uc_microcode[16]; /* at least 8 bytes */
690 } uc[4]; /* microcode values changed historically */
692 RTL_QUERY_REGISTRY_TABLE tab[6] =
694 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
695 L"~Mhz", &cpu_mhz, REG_NONE, NULL, 0 },
696 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
697 L"Update Revision", &uc[0], REG_NONE, NULL, 0 },
698 /* latest MSR */
699 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
700 L"Update Signature", &uc[1], REG_NONE, NULL, 0 },
701 /* previous MSR */
702 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
703 L"CurrentPatchLevel", &uc[2], REG_NONE, NULL, 0 },
704 /* earlier MSR */
705 { NULL, RTL_QUERY_REGISTRY_DIRECT | RTL_QUERY_REGISTRY_NOSTRING,
706 L"Platform Specific Field1", &uc[3], REG_NONE, NULL, 0 },
707 /* alternative */
708 { NULL, 0, NULL, NULL, 0, NULL, 0 }
711 for (size_t uci = 0; uci < sizeof (uc)/sizeof (*uc); ++uci)
713 memset (&uc[uci], 0, sizeof (uc[uci]));
714 uc[uci].uc_len = -(LONG)sizeof (uc[0].uc_microcode);
715 /* neg buffer size */
718 RtlQueryRegistryValues (RTL_REGISTRY_ABSOLUTE, cpu_key, tab,
719 NULL, NULL);
720 cpu_mhz = ((cpu_mhz - 1) / 10 + 1) * 10; /* round up to multiple of 10 */
721 DWORD bogomips = cpu_mhz * 2; /* bogomips is double cpu MHz since MMX */
723 unsigned long long microcode = 0; /* needs 8 bytes */
724 for (size_t uci = 0; uci < sizeof (uc)/sizeof (*uc) && !microcode; ++uci)
726 /* still neg buffer size => no data */
727 if (-(LONG)sizeof (uc[uci].uc_microcode) != uc[uci].uc_len)
729 memcpy (&microcode, uc[uci].uc_microcode, sizeof (microcode));
731 if (!(microcode & 0xFFFFFFFFLL)) /* some values in high bits */
732 microcode >>= 32; /* shift them down */
736 bufptr += __small_sprintf (bufptr, "processor\t: %d\n", cpu_number);
737 uint32_t maxf, vendor_id[4], unused;
739 cpuid (&maxf, &vendor_id[0], &vendor_id[2], &vendor_id[1], 0x00000000);
740 maxf &= 0xffff;
741 vendor_id[3] = 0;
743 /* Vendor identification. */
744 bool is_amd = false, is_intel = false;
745 if (!strcmp ((char*)vendor_id, "AuthenticAMD")
746 || !strcmp((char*)vendor_id, "HygonGenuine"))
747 is_amd = true;
748 else if (!strcmp ((char*)vendor_id, "GenuineIntel"))
749 is_intel = true;
751 bufptr += __small_sprintf (bufptr, "vendor_id\t: %s\n",
752 (char *)vendor_id);
754 uint32_t features1, features2, extra_info, cpuid_sig;
755 cpuid (&cpuid_sig, &extra_info, &features2, &features1, 0x00000001);
756 uint32_t family = (cpuid_sig & 0x00000f00) >> 8,
757 model = (cpuid_sig & 0x000000f0) >> 4,
758 stepping = cpuid_sig & 0x0000000f,
759 apic_id = (extra_info & 0xff000000) >> 24;
760 if (family == 15)
761 family += (cpuid_sig >> 20) & 0xff;
762 if (family >= 6)
763 model |= ((cpuid_sig >> 16) & 0x0f) << 4; /* ext model << 4 | model */
765 uint32_t maxe = 0;
766 cpuid (&maxe, &unused, &unused, &unused, 0x80000000);
767 if (maxe >= 0x80000004)
769 cpuid (&in_buf.m[0], &in_buf.m[1], &in_buf.m[2],
770 &in_buf.m[3], 0x80000002);
771 cpuid (&in_buf.m[4], &in_buf.m[5], &in_buf.m[6],
772 &in_buf.m[7], 0x80000003);
773 cpuid (&in_buf.m[8], &in_buf.m[9], &in_buf.m[10],
774 &in_buf.m[11], 0x80000004);
775 in_buf.m[12] = 0;
777 else
779 /* Could implement a lookup table here if someone needs it. */
780 strcpy (in_buf.s, "unknown");
782 int cache_size = -1,
783 clflush = 64,
784 cache_alignment = 64;
785 long (*get_cpu_cache) (int, uint32_t) = NULL;
786 uint32_t max;
787 if (features1 & (1 << 19)) /* CLFSH */
788 clflush = ((extra_info >> 8) & 0xff) << 3;
789 if (is_intel && family == 15)
790 cache_alignment = clflush * 2;
791 if (is_intel)
793 extern long get_cpu_cache_intel (int sysc, uint32_t maxf);
794 get_cpu_cache = get_cpu_cache_intel;
795 max = maxf; /* Intel uses normal cpuid levels */
797 else if (is_amd)
799 extern long get_cpu_cache_amd (int sysc, uint32_t maxe);
800 get_cpu_cache = get_cpu_cache_amd;
801 max = maxe; /* AMD uses extended cpuid levels */
803 if (get_cpu_cache)
805 long cs;
807 cs = get_cpu_cache (_SC_LEVEL3_CACHE_SIZE, max);
808 if (cs <= 0)
809 cs = get_cpu_cache (_SC_LEVEL2_CACHE_SIZE, max);
810 if (cs <= 0)
812 cs = get_cpu_cache (_SC_LEVEL1_ICACHE_SIZE, max);
813 if (cs > 0)
814 cache_size = cs;
815 cs = get_cpu_cache (_SC_LEVEL1_DCACHE_SIZE, max);
816 if (cs > 0)
817 cache_size += cs;
819 else
820 cache_size = cs;
821 if (cache_size > 0)
822 cache_size >>= 10;
824 bufptr += __small_sprintf (bufptr, "cpu family\t: %d\n"
825 "model\t\t: %d\n"
826 "model name\t: %s\n"
827 "stepping\t: %d\n"
828 "microcode\t: 0x%X\n"
829 "cpu MHz\t\t: %d.000\n",
830 family,
831 model,
832 in_buf.s + strspn (in_buf.s, " \t"),
833 stepping,
834 microcode,
835 cpu_mhz);
837 if (cache_size >= 0)
838 bufptr += __small_sprintf (bufptr, "cache size\t: %d KB\n",
839 cache_size);
841 /* Recognize multi-core CPUs. */
842 if (features1 & (1 << 28)) /* HTT */
844 uint32_t siblings = 0;
845 uint32_t cpu_cores = 0;
846 uint32_t phys_id = 0;
847 uint32_t core_id = 0;
848 uint32_t initial_apic_id = apic_id;
850 uint32_t logical_bits = 0; /* # of logical core bits in apicid. */
851 uint32_t ht_bits = 0; /* # of thread bits in apic_id. */
853 if (is_intel)
855 bool valid = false;
856 if (maxf >= 0x0000000b) /* topoext supported? */
858 uint32_t bits, logical, level, unused;
860 /* Threads */
861 cpuid (&bits, &logical, &level, &unused,
862 0x0000000b, 0x00);
863 /* Even if topoext is supposedly supported, it can return
864 "invalid". */
865 if (bits != 0 && ((level >> 8) & 0xff) == 1)
867 valid = true;
868 ht_bits = (bits & 0x1f);
869 siblings = (logical & 0xffff);
870 cpu_cores = siblings;
871 for (uint32_t idx = 1; ; ++idx)
873 cpuid (&bits, &logical, &level, &initial_apic_id,
874 0x0000000b, idx);
876 uint32_t level_type = ((level >> 8) & 0xff);
877 if (level_type == 0) /* Invalid */
878 break;
879 if (level_type == 2) /* Core */
881 logical_bits = (bits & 0x1f);
882 siblings = (logical & 0xffff);
883 cpu_cores = siblings >> ht_bits;
884 break;
889 if (!valid && maxf >= 0x00000004)
891 uint32_t apic_reserved;
893 cpuid (&apic_reserved, &unused, &unused, &unused,
894 0x00000004, 0x00);
895 if (apic_reserved & 0x1f)
897 valid = true;
898 cpu_cores = ((apic_reserved >> 26) & 0x3f) + 1;
899 siblings = (extra_info >> 16) & 0xff;
900 if (siblings <= 1) /* HT could be fused out */
902 logical_bits = mask_bits (cpu_cores);
903 ht_bits = 0;
905 else
907 logical_bits = mask_bits (siblings);
908 ht_bits = mask_bits (siblings / cpu_cores);
912 if (!valid) /* single core, multi thread */
914 cpu_cores = 1;
915 siblings = (extra_info >> 16) & 0xff;
916 logical_bits = mask_bits (siblings);
917 ht_bits = logical_bits;
920 else if (is_amd)
922 if (maxe >= 0x8000001e)
924 uint32_t cus, core_info;
926 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
927 cpuid (&unused, &cus, &unused, &unused, 0x8000001e);
928 siblings = cpu_cores = (core_info & 0xff) + 1;
929 logical_bits = (core_info >> 12) & 0xf;
930 cus = ((cus >> 8) & 0x3) + 1;
931 ht_bits = mask_bits (cus);
933 else if (maxe >= 0x80000008)
935 uint32_t core_info;
937 cpuid (&unused, &unused, &core_info, &unused, 0x80000008);
938 siblings = (core_info & 0xff) + 1;
939 cpu_cores = siblings;
940 logical_bits = (core_info >> 12) & 0xf;
941 if (!logical_bits)
942 logical_bits = mask_bits (siblings);
943 ht_bits = 0;
945 else
947 siblings = (extra_info >> 16) & 0xff;
948 cpu_cores = siblings;
949 logical_bits = mask_bits (siblings);
950 ht_bits = 0;
953 phys_id = initial_apic_id >> logical_bits;
954 core_id = (initial_apic_id & ((1 << logical_bits) - 1)) >> ht_bits;
956 bufptr += __small_sprintf (bufptr, "physical id\t: %d\n", phys_id);
957 bufptr += __small_sprintf (bufptr, "siblings\t: %u\n", siblings);
958 bufptr += __small_sprintf (bufptr, "core id\t\t: %d\n"
959 "cpu cores\t: %d\n",
960 core_id, cpu_cores);
961 if (features1 & (1 << 9)) /* apic */
962 bufptr += __small_sprintf (bufptr, "apicid\t\t: %d\n"
963 "initial apicid\t: %d\n",
964 apic_id, initial_apic_id);
967 else
969 /* Linux prints all this info depending on CONFIG_SMP. There's no
970 check if the CPU is actually a multicore CPU. */
971 bufptr += __small_sprintf (bufptr, "physical id\t: %d\n", cpu_number);
972 bufptr += __small_sprintf (bufptr, "siblings\t: 1\n");
973 bufptr += __small_sprintf (bufptr, "core id\t\t: 0\n"
974 "cpu cores\t: 1\n");
975 bufptr += __small_sprintf (bufptr, "apicid\t\t: %d\n"
976 "initial apicid\t: %d\n",
977 apic_id, apic_id);
980 /* level is number of non-zero leafs exc. sub-leafs */
981 int level = maxf + 1 + (maxe & 0x7fffffff) + 1;
983 for (uint32_t l = maxe; 0x80000001 < l; --l)
985 uint32_t a, b, c, d;
986 cpuid (&a, &b, &c, &d, l);
987 if (!(a | b | c | d)) --level;
990 for (uint32_t l = maxf; 1 < l; --l)
992 uint32_t a, b, c, d;
993 cpuid (&a, &b, &c, &d, l);
994 if (!(a | b | c | d)) --level;
997 bufptr += __small_sprintf (bufptr, "fpu\t\t: %s\n"
998 "fpu_exception\t: %s\n"
999 "cpuid level\t: %d\n"
1000 "wp\t\t: yes\n",
1001 (features1 & (1 << 0)) ? "yes" : "no",
1002 (features1 & (1 << 0)) ? "yes" : "no",
1003 level);
1004 print ("flags\t\t:");
1005 /* cpuid 0x00000001 edx */
1006 ftcprint (features1, 0, "fpu"); /* x87 floating point */
1007 ftcprint (features1, 1, "vme"); /* VM enhancements */
1008 ftcprint (features1, 2, "de"); /* debugging extensions */
1009 ftcprint (features1, 3, "pse"); /* page size extensions */
1010 ftcprint (features1, 4, "tsc"); /* rdtsc/p */
1011 ftcprint (features1, 5, "msr"); /* rd/wrmsr */
1012 ftcprint (features1, 6, "pae"); /* phy addr extensions */
1013 ftcprint (features1, 7, "mce"); /* Machine check exception */
1014 ftcprint (features1, 8, "cx8"); /* cmpxchg8b */
1015 ftcprint (features1, 9, "apic"); /* APIC enabled */
1016 ftcprint (features1, 11, "sep"); /* sysenter/sysexit */
1017 ftcprint (features1, 12, "mtrr"); /* memory type range registers */
1018 ftcprint (features1, 13, "pge"); /* page global extension */
1019 ftcprint (features1, 14, "mca"); /* machine check architecture */
1020 ftcprint (features1, 15, "cmov"); /* conditional move */
1021 ftcprint (features1, 16, "pat"); /* page attribute table */
1022 ftcprint (features1, 17, "pse36");/* 36 bit page size extensions */
1023 ftcprint (features1, 18, "pn"); /* processor serial number */
1024 ftcprint (features1, 19, "clflush"); /* clflush instruction */
1025 ftcprint (features1, 21, "dts"); /* debug store */
1026 ftcprint (features1, 22, "acpi"); /* ACPI via MSR */
1027 ftcprint (features1, 23, "mmx"); /* multimedia extensions */
1028 ftcprint (features1, 24, "fxsr"); /* fxsave/fxrstor */
1029 ftcprint (features1, 25, "sse"); /* xmm sse */
1030 ftcprint (features1, 26, "sse2"); /* xmm2 sse2 */
1031 ftcprint (features1, 27, "ss"); /* CPU self snoop */
1032 ftcprint (features1, 28, "ht"); /* hyper threading */
1033 ftcprint (features1, 29, "tm"); /* acc automatic clock control */
1034 ftcprint (features1, 30, "ia64"); /* IA 64 processor */
1035 ftcprint (features1, 31, "pbe"); /* pending break enable */
1037 /* AMD cpuid 0x80000001 edx */
1038 if (is_amd && maxe >= 0x80000001)
1040 cpuid (&unused, &unused, &unused, &features1, 0x80000001);
1042 ftcprint (features1, 11, "syscall"); /* syscall/sysret */
1043 ftcprint (features1, 19, "mp"); /* MP capable */
1044 ftcprint (features1, 20, "nx"); /* no-execute protection */
1045 ftcprint (features1, 22, "mmxext"); /* MMX extensions */
1046 ftcprint (features1, 25, "fxsr_opt"); /* fxsave/fxrstor optims */
1047 ftcprint (features1, 26, "pdpe1gb"); /* GB large pages */
1048 ftcprint (features1, 27, "rdtscp"); /* rdtscp */
1049 ftcprint (features1, 29, "lm"); /* long mode (x86-64 amd64) */
1050 ftcprint (features1, 30, "3dnowext"); /* 3DNow extensions */
1051 ftcprint (features1, 31, "3dnow"); /* 3DNow */
1054 /* cpuid 0x80000007 edx */
1055 if (maxe >= 0x80000007)
1057 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1059 ftcprint (features1, 8, "constant_tsc"); /* TSC ticks at a constant rate */
1062 /* ftcprint (features2, 9, "up"); *//* SMP kernel running on UP N/A */
1064 /* cpuid 0x00000007 ebx */
1065 if (maxf >= 0x00000007)
1066 cpuid (&unused, &features1, &unused, &unused, 0x00000007, 0);
1067 else
1068 features1 = 0;
1069 /* cpuid 0x80000007 edx */
1070 if (maxe >= 0x80000007)
1071 cpuid (&unused, &unused, &unused, &features2, 0x80000007);
1072 else
1073 features2 = 0;
1074 uint32_t cr_den, cr_num, Hz;
1075 /* cpuid 0x00000015 eax ebx ecx clock ratios optional Hz */
1076 if (is_intel && maxf >= 0x00000015)
1077 cpuid (&cr_den, &cr_num, &Hz, &unused, 0x00000015);
1078 else
1079 cr_den = 0;
1080 /* TSC requires adjustment, nonstop, and clock ratio divider min */
1081 if ((features1 & (1 << 1)) && /* TSC adjustment MSR 0x3B */
1082 (features2 & (1 << 8)) && /* nonstop C states */
1083 (cr_den > 1)) /* clock ratio denominator > min */
1084 ftuprint ("art"); /* Always running timer (ART) */
1086 /* Intel cpuid 0x0000000a eax Arch Perf Mon */
1087 if (is_intel && maxf >= 0x0000000a)
1089 cpuid (&features2, &unused, &unused, &unused, 0x0000000a);
1091 /* rev > 0 and # counters/cpu > 1 */
1092 if ((features2 & 0xff) > 0 && (((features2 >> 8) & 0xff) > 1))
1093 ftuprint ("arch_perfmon"); /* Intel Arch Perf Mon */
1096 /* ftcprint (features2, 12, "pebs");*//* MSR_IA32_MISC_ENABLE 12 Precise-Event Based Sampling */
1097 /* ftcprint (features2, 13, "bts"); *//* MSR_IA32_MISC_ENABLE 11 Branch Trace Store */
1099 /* AMD cpuid 0x00000001 eax */
1100 if (is_amd && maxf >= 0x00000001)
1101 cpuid(&features2, &unused, &unused, &unused, 0x00000001);
1102 else
1103 features2 = 0;
1105 /* Intel family 6 or AMD family >= x10 or ... */
1106 /* ... or AMD cpuid 0x00000001 eax in [0x0f58,) or [0x0f48,0x0f50) */
1107 if ((is_intel && family == 6) ||
1108 (is_amd && (family >= 0x10 ||
1109 (features2 >= 0x0f58 ||
1110 (features2 >= 0x0f48 && features2 < 0x0f50)))))
1111 ftuprint ("rep_good"); /* REP microcode works well */
1113 /* cpuid 0x80000007 edx Advanced power management */
1114 if (maxe >= 0x80000007)
1116 cpuid (&unused, &unused, &unused, &features2, 0x80000007);
1118 ftcprint (features2, 12, "acc_power"); /* accum power */
1121 ftuprint ("nopl"); /* NOPL (0F 1F) instructions */
1123 /* cpuid 0x0000000b ecx[8:15] type */
1124 #define BAD_TYPE 0
1125 #define SMT_TYPE 1
1126 #define CORE_TYPE 2
1127 /* cpuid 0x0000000b ebx ecx */
1128 if (maxf >= 0x0000000b)
1130 cpuid(&unused, &features1, &features2, &unused, 0x0000000b);
1132 /* check if SMT implemented */
1133 if (features1 != 0 && (((features2 >> 8) & 0xff) == SMT_TYPE))
1134 ftuprint ("xtopology"); /* CPU topology enum extensions */
1137 /* AMD cpuid 0x80000007 edx */
1138 if (is_amd && maxe >= 0x80000007)
1140 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1142 ftcprint (features1, 8, "tsc_reliable"); /* TSC constant rate */
1143 ftcprint (features1, 8, "nonstop_tsc"); /* nonstop C states */
1146 if (is_amd || is_intel)
1147 ftuprint ("cpuid"); /* CPU has CPUID instruction */
1149 if (is_amd && family > 0x16)
1150 ftuprint ("extd_apicid"); /* Extended APICID (8 bits) */
1152 /* AMD cpuid 0x8000001e ecx */
1153 if (is_amd && maxe >= 0x8000001e)
1155 cpuid (&unused, &unused, &features1, &unused, 0x8000001e);
1157 if (((features1 >> 8) & 7) + 1 > 1) /* nodes/socket */
1158 ftuprint ("amd_dcm"); /* AMD multi-node processor */
1161 /* cpuid 0x00000006 ecx */
1162 if (maxf >= 0x00000006)
1164 cpuid (&unused, &unused, &features1, &unused, 0x00000006);
1166 ftcprint (features1, 0, "aperfmperf"); /* P state hw coord fb */
1169 /* cpuid 0x80000007 edx Advanced power management */
1170 if (maxe >= 0x80000007)
1172 cpuid (&unused, &unused, &unused, &features2, 0x80000007);
1174 ftcprint (features2, 14, "rapl"); /* runtime avg power limit */
1177 /* Penwell, Cloverview, ... TSC doesn't sleep on S3 */
1178 if (is_intel && family == 6)
1179 switch (model)
1181 case 0x27: /* Atom Saltwell Mid Penwell */
1182 case 0x35: /* Atom Saltwell Tablet Cloverview */
1183 case 0x4a: /* Atom Silvermont Mid Merriefield */
1184 case 0x75: /* Atom Airmont NP Lightning Mountain */
1185 ftuprint ("nonstop_tsc_s3"); /* TSC doesn't stop in S3 state */
1186 break;
1189 /* cpuid 0x00000015 eax ebx ecx clock ratios optional Hz */
1190 if (is_intel && maxf >= 0x00000015)
1192 uint32_t cr_den, cr_num, Hz, kHz;
1193 cpuid (&cr_den, &cr_num, &Hz, &unused, 0x00000015);
1194 if (cr_num != 0 && cr_den != 0)
1196 kHz = Hz / 1000;
1197 /* Denverton don't report hz nor support cpuid 0x16 so set 25MHz */
1198 if (kHz == 0 && model == 0x5F) /* Atom Goldmont D Denverton */
1199 kHz = 25000;
1201 /* cpuid TSC frequency is known */
1202 if (kHz != 0)
1203 ftuprint ("tsc_known_freq"); /* TSC has known frequency */
1204 #if 0 /* keep for future and doc */
1205 else /* kHz == 0 */
1206 /* Skylake and Kabylake don't report clock so use CPU speed and ratio */
1207 if (maxf >= 0x00000016)
1209 uint32_t mHz;
1210 cpuid(&mHz, &unused, &unused, &unused, 0x00000016);
1211 kHz = mHz * 1000 * cr_num / cr_den;
1213 #endif
1217 /* cpuid 0x00000001 ecx */
1218 cpuid (&unused, &unused, &features2, &unused, 0x00000001);
1220 ftcprint (features2, 0, "pni"); /* xmm3 sse3 */
1221 ftcprint (features2, 1, "pclmuldq"); /* pclmulqdq instruction */
1222 ftcprint (features2, 2, "dtes64"); /* 64-bit debug store */
1223 ftcprint (features2, 3, "monitor"); /* monitor/mwait support */
1224 ftcprint (features2, 4, "ds_cpl"); /* CPL-qual debug store */
1225 ftcprint (features2, 5, "vmx"); /* hardware virtualization */
1226 ftcprint (features2, 6, "smx"); /* safer mode extensions */
1227 ftcprint (features2, 7, "est"); /* enhanced speedstep */
1228 ftcprint (features2, 8, "tm2"); /* thermal monitor 2 */
1229 ftcprint (features2, 9, "ssse3"); /* supplemental sse3 */
1230 ftcprint (features2, 10, "cid"); /* context id */
1231 ftcprint (features2, 11, "sdbg"); /* silicon debug */
1232 ftcprint (features2, 12, "fma"); /* fused multiply add */
1233 ftcprint (features2, 13, "cx16"); /* cmpxchg16b instruction */
1234 ftcprint (features2, 14, "xtpr"); /* send task priority messages */
1235 ftcprint (features2, 15, "pdcm"); /* perf/debug capabilities MSR */
1236 ftcprint (features2, 17, "pcid"); /* process context identifiers */
1237 ftcprint (features2, 18, "dca"); /* direct cache access */
1238 ftcprint (features2, 19, "sse4_1"); /* xmm 4_1 sse 4.1 */
1239 ftcprint (features2, 20, "sse4_2"); /* xmm 4_2 sse 4.2 */
1240 ftcprint (features2, 21, "x2apic"); /* x2 APIC */
1241 ftcprint (features2, 22, "movbe"); /* movbe instruction */
1242 ftcprint (features2, 23, "popcnt"); /* popcnt instruction */
1243 ftcprint (features2, 24, "tsc_deadline_timer"); /* TSC deadline timer */
1244 ftcprint (features2, 25, "aes"); /* AES instructions */
1245 ftcprint (features2, 26, "xsave"); /* xsave/xrstor/xsetbv/xgetbv */
1246 /* ftcprint (features2, 27, "osxsave");*//* "" XSAVE supported in OS */
1247 ftcprint (features2, 28, "avx"); /* advanced vector extensions */
1248 ftcprint (features2, 29, "f16c"); /* 16 bit FP conversions */
1249 ftcprint (features2, 30, "rdrand"); /* RNG rdrand instruction */
1250 ftcprint (features2, 31, "hypervisor"); /* hypervisor guest */
1252 /* cpuid 0x80000001 ecx */
1253 if (maxe >= 0x80000001)
1255 cpuid (&unused, &unused, &features1, &unused, 0x80000001);
1257 ftcprint (features1, 0, "lahf_lm"); /* l/sahf long mode */
1258 ftcprint (features1, 1, "cmp_legacy"); /* HT not valid */
1259 if (is_amd)
1261 ftcprint (features1, 2, "svm"); /* secure VM */
1262 ftcprint (features1, 3, "extapic"); /* ext APIC space */
1263 ftcprint (features1, 4, "cr8_legacy"); /* CR8 32 bit mode */
1264 ftcprint (features1, 5, "abm"); /* adv bit manip lzcnt */
1265 ftcprint (features1, 6, "sse4a"); /* sse 4a */
1266 ftcprint (features1, 7, "misalignsse"); /* misaligned SSE ok */
1267 ftcprint (features1, 8, "3dnowprefetch"); /* 3DNow prefetch */
1268 ftcprint (features1, 9, "osvw"); /* OS vis workaround */
1270 ftcprint (features1, 10, "ibs"); /* instr based sampling */
1271 if (is_amd)
1273 ftcprint (features1, 11, "xop"); /* sse 5 extended AVX */
1274 ftcprint (features1, 12, "skinit"); /* skinit/stgi */
1275 ftcprint (features1, 13, "wdt"); /* watchdog timer */
1276 ftcprint (features1, 15, "lwp"); /* light weight prof */
1277 ftcprint (features1, 16, "fma4"); /* 4 operand MAC */
1278 ftcprint (features1, 17, "tce"); /* translat cache ext */
1279 ftcprint (features1, 19, "nodeid_msr"); /* nodeid MSR */
1280 ftcprint (features1, 21, "tbm"); /* trailing bit manip */
1281 ftcprint (features1, 22, "topoext"); /* topology ext */
1282 ftcprint (features1, 23, "perfctr_core"); /* core perf ctr ext */
1283 ftcprint (features1, 24, "perfctr_nb"); /* NB perf ctr ext */
1284 ftcprint (features1, 26, "bpext"); /* data brkpt ext */
1285 ftcprint (features1, 27, "ptsc"); /* perf timestamp ctr */
1286 ftcprint (features1, 28, "perfctr_llc"); /* ll cache perf ctr */
1287 ftcprint (features1, 29, "mwaitx"); /* monitor/mwaitx ext */
1291 /* ring 3 monitor/mwait */
1292 if (is_intel && family == 6)
1293 switch (model)
1295 case 0x57: /* Xeon Phi Knights Landing */
1296 case 0x85: /* Xeon Phi Knights Mill */
1297 ftuprint ("ring3mwait"); /* Ring 3 MONITOR/MWAIT instructions */
1298 break;
1301 /* ftcprint (features1, 1, "cpuid_fault");*//* MSR_PLATFORM_INFO Intel CPUID faulting */
1303 /* features scattered in various CPUID levels. */
1304 /* cpuid 0x80000007 edx */
1305 if (maxe >= 0x80000007)
1307 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1309 ftcprint (features1, 9, "cpb"); /* core performance boost */
1311 /* cpuid 0x00000006 ecx */
1312 if (maxf >= 0x00000006)
1314 cpuid (&unused, &unused, &features1, &unused, 0x00000006);
1316 ftcprint (features1, 3, "epb"); /* energy perf bias */
1318 /* cpuid 0x00000007:1 ebx */
1319 if (maxf >= 0x00000007)
1321 cpuid (&unused, &features1, &unused, &unused, 0x00000007, 1);
1323 ftcprint (features1, 0, "intel_ppin"); /* Prot Proc Id No */
1325 /* cpuid 0x00000010 ebx */
1326 if (maxf >= 0x00000010)
1328 cpuid (&unused, &features1, &unused, &unused, 0x00000010);
1330 ftcprint (features1, 1, "cat_l3"); /* cache alloc tech l3 */
1331 ftcprint (features1, 2, "cat_l2"); /* cache alloc tech l2 */
1333 /* cpuid 0x00000010:1 ecx */
1334 cpuid (&unused, &unused, &features1, &unused, 0x00000010, 1);
1336 ftcprint (features1, 2, "cdp_l3"); /* code data prior l3 */
1339 /* ftcprint (features1, 7, "invpcid_single");*//* INVPCID && CR4.PCIDE=1 */
1341 /* cpuid 0x80000007 edx */
1342 if (maxe >= 0x80000007)
1344 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1346 ftcprint (features1, 7, "hw_pstate"); /* hw P state */
1347 ftcprint (features1, 11, "proc_feedback"); /* proc feedback interf */
1350 /* ftcprint (features1, 11, "pti");*//* Page Table Isolation reqd with Meltdown */
1352 /* cpuid 0x00000010:2 ecx */
1353 if (maxf >= 0x00000010)
1355 cpuid (&unused, &unused, &features2, &unused, 0x00000010, 2);
1357 ftcprint (features2, 2, "cdp_l2"); /* code data prior l2 */
1359 /* cpuid 0x80000008 ebx */
1360 if (maxe >= 0x80000008)
1362 cpuid (&unused, &features1, &unused, &unused, 0x80000008, 0);
1364 ftcprint (features1, 24, "ssbd"); /* spec store byp dis */
1366 /* cpuid 0x00000010 ebx */
1367 if (maxf >= 0x00000010)
1369 cpuid (&unused, &features2, &unused, &unused, 0x00000010);
1371 ftcprint (features2, 3, "mba"); /* memory bandwidth alloc */
1373 /* cpuid 0x80000008 ebx */
1374 if (maxe >= 0x80000008)
1376 /* cpuid (&unused, &features1, &unused, &unused, 0x80000008, 0); */
1377 /* from above ^ */
1378 ftcprint (features1, 6, "mba"); /* memory bandwidth alloc */
1380 /* cpuid 0x80000022 ebx AMD ExtPerfMonAndDbg */
1381 if (maxe >= 0x80000022)
1383 cpuid (&features2, &unused, &unused, &unused, 0x80000022);
1385 ftcprint (features2, 0, "perfmon_v2"); /* Performance Monitoring Version 2 */
1387 /* AMD cpuid 0x80000008 ebx */
1388 if (is_amd && maxe >= 0x80000008)
1390 /* cpuid (&unused, &features1, &unused, &unused, 0x80000008, 0); */
1391 /* from above ^ */
1392 /* ftcprint (features1, 0, "clzero"); *//* clzero instruction */
1393 /* ftcprint (features1, 1, "irperf"); *//* instr retired count */
1394 /* ftcprint (features1, 2, "xsaveerptr");*//* save/rest FP err ptrs */
1395 /* ftcprint (features1, 4, "rdpru"); *//* user level rd proc reg */
1396 /* ftcprint (features1, 6, "mba"); *//* memory BW alloc */
1397 /* ftcprint (features1, 9, "wbnoinvd"); *//* wbnoinvd instruction */
1398 ftcprint (features1, 12, "ibpb"); /* ind br pred barrier */
1399 ftcprint (features1, 14, "ibrs"); /* ind br restricted spec */
1400 ftcprint (features1, 15, "stibp"); /* 1 thread ind br pred */
1401 ftcprint (features1, 16, "ibrs_enhanced"); /* ibrs_enhanced IBRS always on */
1402 /* ftcprint (features1, 17, "stibp_always_on"); */ /* stibp always on */
1403 /* ftcprint (features1, 18, "ibrs_pref");*//* ibrs_pref IBRS preferred */
1404 /* ftcprint (features1, 23, "amd_ppin"); *//* protected proc id no */
1405 /* ftcprint (features1, 24, "ssbd"); *//* spec store byp dis */
1406 /* ftcprint (features1, 25, "virt_ssbd");*//* vir spec store byp dis */
1407 /* ftcprint (features1, 26, "ssb_no"); *//* ssb fixed in hardware */
1408 /* ftcprint (features1, 27, "cppc"); *//* collab proc perf ctl */
1409 /* ftcprint (features1, 28, "amd_psfd"); *//* predictive store fwd dis */
1410 /* ftcprint (features1, 31, "brs"); *//* branch sampling */
1413 /* cpuid 0x00000021 ebx|edx|ecx == "IntelTDX " */
1414 if (is_intel && maxf >= 0x00000021)
1416 uint32_t tdx[3];
1418 cpuid (&unused, &tdx[0], &tdx[2], &tdx[1], 0x00000021, 0);
1419 if (!memcmp ("IntelTDX ", tdx, sizeof (tdx)))
1420 ftuprint ("tdx_guest"); /* Intel Trust Domain Extensions Guest Support */
1423 /* cpuid 0x00000007 ebx */
1424 if (maxf >= 0x00000007)
1426 cpuid (&unused, &features1, &unused, &unused, 0x00000007, 0);
1428 ftcprint (features1, 0, "fsgsbase"); /* rd/wr fs/gs base */
1429 ftcprint (features1, 1, "tsc_adjust"); /* TSC adjustment MSR 0x3B */
1430 ftcprint (features1, 2, "sgx"); /* software guard extensions */
1431 ftcprint (features1, 3, "bmi1"); /* bit manip ext group 1 */
1432 ftcprint (features1, 4, "hle"); /* hardware lock elision */
1433 ftcprint (features1, 5, "avx2"); /* AVX ext instructions */
1434 /* ftcprint (features1, 6, "fpdx"); */ /* "" FP data ptr upd on exc */
1435 ftcprint (features1, 7, "smep"); /* super mode exec prot */
1436 ftcprint (features1, 8, "bmi2"); /* bit manip ext group 2 */
1437 ftcprint (features1, 9, "erms"); /* enh rep movsb/stosb */
1438 ftcprint (features1, 10, "invpcid"); /* inv proc context id */
1439 ftcprint (features1, 11, "rtm"); /* restricted txnal mem */
1440 ftcprint (features1, 12, "cqm"); /* cache QoS monitoring */
1441 /* ftcprint (features1, 13, "fpcsdsz"); */ /* "" zero FP cs/ds */
1442 ftcprint (features1, 14, "mpx"); /* mem prot ext */
1443 ftcprint (features1, 15, "rdt_a"); /* rsrc dir tech alloc */
1444 ftcprint (features1, 16, "avx512f"); /* vec foundation */
1445 ftcprint (features1, 17, "avx512dq"); /* vec dq granular */
1446 ftcprint (features1, 18, "rdseed"); /* RNG rdseed instruction */
1447 ftcprint (features1, 19, "adx"); /* adcx/adox */
1448 ftcprint (features1, 20, "smap"); /* sec mode access prev */
1449 ftcprint (features1, 21, "avx512ifma"); /* vec int FMA */
1450 ftcprint (features1, 23, "clflushopt"); /* cache line flush opt */
1451 ftcprint (features1, 24, "clwb"); /* cache line write back */
1452 ftcprint (features1, 25, "intel_pt"); /* intel processor trace */
1453 ftcprint (features1, 26, "avx512pf"); /* vec prefetch */
1454 ftcprint (features1, 27, "avx512er"); /* vec exp/recip aprx */
1455 ftcprint (features1, 28, "avx512cd"); /* vec conflict detect */
1456 ftcprint (features1, 29, "sha_ni"); /* SHA extensions */
1457 ftcprint (features1, 30, "avx512bw"); /* vec byte/word gran */
1458 ftcprint (features1, 31, "avx512vl"); /* vec vec len ext */
1461 /* more random feature flags */
1462 /* cpuid 0x0000000d:1 eax */
1463 if (maxf >= 0x0000000d)
1465 cpuid (&features1, &unused, &unused, &unused, 0x0000000d, 1);
1467 ftcprint (features1, 0, "xsaveopt"); /* xsaveopt instruction */
1468 ftcprint (features1, 1, "xsavec"); /* xsavec instruction */
1469 ftcprint (features1, 2, "xgetbv1"); /* xgetbv ecx 1 */
1470 ftcprint (features1, 3, "xsaves"); /* xsaves/xrstors */
1472 /* cpuid 0x0000000f edx */
1473 if (maxf >= 0x0000000f)
1475 cpuid (&unused, &unused, &unused, &features1, 0x0000000f);
1477 ftcprint (features1, 1, "cqm_llc"); /* llc QoS */
1479 /* cpuid 0x0000000f:1 edx */
1480 cpuid (&unused, &unused, &unused, &features1, 0x0000000f, 1);
1482 ftcprint (features1, 0, "cqm_occup_llc"); /* llc occup monitor */
1483 ftcprint (features1, 1, "cqm_mbm_total"); /* llc total MBM mon */
1484 ftcprint (features1, 2, "cqm_mbm_local"); /* llc local MBM mon */
1487 /* ftcprint (features1, 6, "split_lock_detect");*//* MSR_TEST_CTRL split lock */
1489 /* Windows [20]20H1/[20]2004/19041 user shadow stack */
1490 if (maxf >= 0x00000007 && wincap.has_user_shstk ())
1492 /* cpuid 0x00000007 ecx CET shadow stack */
1493 cpuid (&unused, &unused, &features1, &unused, 0x00000007, 0);
1494 ftcprint (features1, 7, "user_shstk"); /* user shadow stack */
1497 /* cpuid 0x00000007:1 eax */
1498 if (maxf >= 0x00000007)
1500 cpuid (&features1, &unused, &unused, &unused, 0x00000007, 1);
1502 ftcprint (features1, 4, "avx_vnni"); /* vex enc NN vec */
1503 ftcprint (features1, 5, "avx512_bf16"); /* vec bfloat16 short */
1504 /* ftcprint (features1, 7, "cmpccxadd"); */ /* CMPccXADD instructions */
1505 /* ftcprint (features1, 18, "lkgs"); */ /* load kernel (userspace) GS */
1506 /* ftcprint (features1, 21, "amx_fp16"); */ /* AMX fp16 Support */
1507 /* ftcprint (features1, 23, "avx_ifma"); */ /* Support for VPMADD52[H,L]UQ */
1508 ftcprint (features1, 26, "lam"); /* Linear Address Masking */
1511 /* AMD cpuid 0x80000008 ebx */
1512 if (is_amd && maxe >= 0x80000008)
1514 cpuid (&unused, &features1, &unused, &unused, 0x80000008, 0);
1516 ftcprint (features1, 0, "clzero"); /* clzero instruction */
1517 ftcprint (features1, 1, "irperf"); /* instr retired count */
1518 ftcprint (features1, 2, "xsaveerptr"); /* save/rest FP err ptrs */
1519 ftcprint (features1, 4, "rdpru"); /* user level rd proc reg */
1520 /* ftcprint (features1, 6, "mba"); */ /* memory BW alloc */
1521 ftcprint (features1, 9, "wbnoinvd"); /* wbnoinvd instruction */
1522 /* ftcprint (features1, 12, "ibpb" ); */ /* ind br pred barrier */
1523 /* ftcprint (features1, 14, "ibrs" ); */ /* ind br restricted spec */
1524 /* ftcprint (features1, 15, "stibp"); */ /* 1 thread ind br pred */
1525 /* ftcprint (features1, 16, "ibrs_enhanced"); */ /* ibrs_enhanced IBRS always on */
1526 /* ftcprint (features1, 17, "stibp_always_on"); */ /* stibp always on */
1527 /* ftcprint (features1, 18, "ibrs_pref"); */ /* ibrs_pref IBRS preferred */
1528 ftcprint (features1, 23, "amd_ppin"); /* protected proc id no */
1529 /* ftcprint (features1, 24, "ssbd"); */ /* spec store byp dis */
1530 ftcprint (features1, 25, "virt_ssbd"); /* vir spec store byp dis */
1531 /* ftcprint (features1, 26, "ssb_no"); */ /* ssb fixed in hardware */
1532 ftcprint (features1, 27, "cppc"); /* collab proc perf ctl */
1533 /* ftcprint (features1, 28, "amd_psfd"); */ /* predictive store fwd dis */
1534 ftcprint (features1, 31, "brs"); /* branch sampling */
1537 /* thermal & power cpuid 0x00000006 eax */
1538 if (maxf >= 0x00000006)
1540 cpuid (&features1, &unused, &features2, &unused, 0x00000006);
1542 ftcprint (features1, 0, "dtherm"); /* digital thermal sensor */
1543 ftcprint (features1, 1, "ida"); /* Intel dynamic acceleration */
1544 ftcprint (features1, 2, "arat"); /* always running APIC timer */
1545 ftcprint (features1, 4, "pln"); /* power limit notification */
1546 ftcprint (features1, 6, "pts"); /* package thermal status */
1547 ftcprint (features1, 7, "hwp"); /* hardware P states */
1548 ftcprint (features1, 8, "hwp_notify"); /* HWP notification */
1549 ftcprint (features1, 9, "hwp_act_window"); /* HWP activity window */
1550 ftcprint (features1, 10, "hwp_epp"); /* HWP energy perf pref */
1551 ftcprint (features1, 11, "hwp_pkg_req"); /* HWP package level req */
1552 ftcprint (features1, 19, "hfi"); /* Hardware Feedback Interface */
1555 /* AMD SVM cpuid 0x8000000a edx */
1556 if (is_amd && maxe >= 0x8000000a)
1558 cpuid (&unused, &unused, &unused, &features1, 0x8000000a, 0);
1560 ftcprint (features1, 0, "npt"); /* nested paging */
1561 ftcprint (features1, 1, "lbrv"); /* lbr virtualization */
1562 ftcprint (features1, 2, "svm_lock"); /* SVM locking MSR */
1563 ftcprint (features1, 3, "nrip_save"); /* SVM next rip save */
1564 ftcprint (features1, 4, "tsc_scale"); /* TSC rate control */
1565 ftcprint (features1, 5, "vmcb_clean"); /* VMCB clean bits */
1566 ftcprint (features1, 6, "flushbyasid"); /* flush by ASID */
1567 ftcprint (features1, 7, "decode_assists"); /* decode assists */
1568 ftcprint (features1, 10, "pausefilter"); /* filt pause intrcpt */
1569 ftcprint (features1, 12, "pfthreshold"); /* pause filt thresh */
1570 ftcprint (features1, 13, "avic"); /* virt int control */
1571 ftcprint (features1, 15, "v_vmsave_vmload"); /* virt vmsave vmload */
1572 ftcprint (features1, 16, "vgif"); /* virt glb int flag */
1573 ftcprint (features1, 20, "v_spec_ctrl"); /* virt spec ctrl support */
1574 ftcprint (features1, 25, "vnmi"); /* virt NMI */
1575 /* ftcprint (features1, 28, "svme_addr_chk"); *//* secure vmexit addr check */
1578 /* Intel cpuid 0x00000007 ecx */
1579 if (is_intel && maxf >= 0x00000007)
1581 cpuid (&unused, &unused, &features1, &unused, 0x00000007, 0);
1583 ftcprint (features1, 1, "avx512vbmi"); /* vec bit manip */
1584 ftcprint (features1, 2, "umip"); /* user mode ins prot */
1585 ftcprint (features1, 3, "pku"); /* prot key userspace */
1586 ftcprint (features1, 4, "ospke"); /* OS prot keys en */
1587 ftcprint (features1, 5, "waitpkg"); /* umon/umwait/tpause */
1588 ftcprint (features1, 6, "avx512_vbmi2"); /* vec bit manip 2 */
1589 /* ftcprint (features1, 7, "shstk"); */ /* Shadow stack */
1590 ftcprint (features1, 8, "gfni"); /* Galois field instr */
1591 ftcprint (features1, 9, "vaes"); /* vector AES */
1592 ftcprint (features1, 10, "vpclmulqdq"); /* nc mul dbl quad */
1593 ftcprint (features1, 11, "avx512_vnni"); /* vec neural net */
1594 ftcprint (features1, 12, "avx512_bitalg"); /* vpopcnt/b/w vpshuf */
1595 ftcprint (features1, 13, "tme"); /* total mem encrypt */
1596 ftcprint (features1, 14, "avx512_vpopcntdq"); /* vec popcnt dw/qw */
1597 ftcprint (features1, 16, "la57"); /* 5 level paging */
1598 ftcprint (features1, 22, "rdpid"); /* rdpid instruction */
1599 ftcprint (features1, 24, "bus_lock_detect"); /* bus lock detect dbg excptn */
1600 ftcprint (features1, 25, "cldemote"); /* cldemote instr */
1601 ftcprint (features1, 27, "movdiri"); /* movdiri instr */
1602 ftcprint (features1, 28, "movdir64b"); /* movdir64b instr */
1603 ftcprint (features1, 29, "enqcmd"); /* enqcmd/s instructions*/
1604 ftcprint (features1, 30, "sgx_lc"); /* sgx launch control */
1607 /* AMD MCA cpuid 0x80000007 ebx */
1608 if (is_amd && maxe >= 0x80000007)
1610 cpuid (&unused, &features1, &unused, &unused, 0x80000007, 0);
1612 ftcprint (features1, 0, "overflow_recov"); /* MCA oflow recovery */
1613 ftcprint (features1, 1, "succor"); /* uncor err recovery */
1614 ftcprint (features1, 3, "smca"); /* scalable MCA */
1617 /* Intel cpuid 0x00000007 edx */
1618 if (is_intel && maxf >= 0x00000007)
1620 cpuid (&unused, &unused, &unused, &features1, 0x00000007, 0);
1622 ftcprint (features1, 2, "avx512_4vnniw"); /* vec dot prod dw */
1623 ftcprint (features1, 3, "avx512_4fmaps"); /* vec 4 FMA single */
1624 ftcprint (features1, 4, "fsrm"); /* fast short REP MOVSB */
1625 ftcprint (features1, 8, "avx512_vp2intersect"); /* vec intcpt d/q */
1626 ftcprint (features1, 10, "md_clear"); /* verw clear buf */
1627 ftcprint (features1, 14, "serialize"); /* SERIALIZE instruction */
1628 ftcprint (features1, 16, "tsxldtrk"); /* TSX Susp Ld Addr Track */
1629 ftcprint (features1, 18, "pconfig"); /* platform config */
1630 ftcprint (features1, 19, "arch_lbr"); /* last branch records */
1631 ftcprint (features1, 20, "ibt"); /* Indirect Branch Tracking */
1632 ftcprint (features1, 22, "amx_bf16"); /* Advanced Matrix eXtensions Brain Float 16 dot product */
1633 ftcprint (features1, 23, "avx512_fp16"); /* avx512 fp16 */
1634 ftcprint (features1, 24, "amx_tile"); /* Advanced Matrix eXtensions Tile matrix multiply */
1635 ftcprint (features1, 25, "amx_int8"); /* Advanced Matrix eXtensions Int 8 byte dot product */
1636 ftcprint (features1, 28, "flush_l1d"); /* flush l1d cache */
1637 ftcprint (features1, 29, "arch_capabilities"); /* arch cap MSR */
1640 /* cpuid x8000001f eax */
1641 if (is_amd && maxe >= 0x8000001f)
1643 cpuid (&features2, &unused, &unused, &unused, 0x8000001f);
1645 ftcprint (features2, 0, "sme"); /* secure memory encryption */
1646 ftcprint (features2, 1, "sev"); /* AMD secure encrypted virt */
1647 /* ftcprint (features2, 2, "vm_page_flush");*/ /* VM page flush MSR */
1648 ftcprint (features2, 3, "sev_es"); /* AMD SEV encrypted state */
1649 /* ftcprint (features2, 4, "sev_snp");*//* AMD SEV secure nested paging */
1650 /* ftcprint (features2, 5, "vmpl"); *//* VM permission levels support */
1651 /* ftcprint (features2, 10, "sme_coherent"); *//* SME h/w cache coherent */
1652 /* ftcprint (features2, 11, "sev_64b");*//* SEV 64 bit host guest only */
1653 /* ftcprint (features2, 12, "sev_rest_inj"); *//* SEV restricted injection */
1654 /* ftcprint (features2, 13, "sev_alt_inj"); *//* SEV alternate injection */
1655 ftcprint (features2, 14, "debug_swap"); /* SEV-ES full debug state swap */
1656 /* ftcprint (features2, 15, "no_host_ibs"); *//* host IBS unsupported */
1657 /* ftcprint (features2, 16, "vte"); *//* virtual transparent encryption */
1660 print ("\n");
1662 bufptr += __small_sprintf (bufptr, "bogomips\t: %d.00\n",
1663 bogomips);
1665 /* cpuid 0x80000006 ebx TLB size */
1666 if (maxe >= 0x80000006)
1668 cpuid( &unused, &features1, &unused, &unused, 0x80000006, 0);
1669 uint32_t tlbsize = ((features1 >> 16) & 0xfff) + (features1 & 0xfff);
1670 if (tlbsize > 0)
1671 bufptr += __small_sprintf (bufptr, "TLB size\t: %d 4K pages\n",
1672 tlbsize);
1675 bufptr += __small_sprintf (bufptr, "clflush size\t: %d\n"
1676 "cache_alignment\t: %d\n",
1677 clflush,
1678 cache_alignment);
1680 if (maxe >= 0x80000008) /* Address size. */
1682 uint32_t addr_size, phys, virt;
1683 cpuid (&addr_size, &unused, &unused, &unused, 0x80000008);
1685 phys = addr_size & 0xff;
1686 virt = (addr_size >> 8) & 0xff;
1687 /* Fix an errata on Intel CPUs */
1688 if (is_intel && family == 15 && model == 3 && stepping == 4)
1689 phys = 36;
1690 bufptr += __small_sprintf (bufptr, "address sizes\t: "
1691 "%u bits physical, "
1692 "%u bits virtual\n",
1693 phys, virt);
1696 /* cpuid 0x80000007 edx */
1697 if (maxe >= 0x80000007) /* Advanced power management. */
1699 cpuid (&unused, &unused, &unused, &features1, 0x80000007);
1701 print ("power management:");
1702 ftcprint (features1, 0, "ts"); /* temperature sensor */
1703 ftcprint (features1, 1, "fid"); /* frequency id control */
1704 ftcprint (features1, 2, "vid"); /* voltage id control */
1705 ftcprint (features1, 3, "ttp"); /* thermal trip */
1706 ftcprint (features1, 4, "tm"); /* hw thermal control */
1707 ftcprint (features1, 5, "stc"); /* sw thermal control */
1708 ftcprint (features1, 6, "100mhzsteps"); /* 100 MHz mult control */
1709 ftcprint (features1, 7, "hwpstate"); /* hw P state control */
1710 /* ftcprint (features1, 8, "invariant_tsc"); */ /* TSC invariant */
1711 ftcprint (features1, 9, "cpb"); /* core performance boost */
1712 ftcprint (features1, 10, "eff_freq_ro"); /* ro eff freq interface */
1713 ftcprint (features1, 11, "proc_feedback");/* proc feedback if */
1714 ftcprint (features1, 12, "acc_power"); /* core power reporting */
1715 /* ftcprint (features1, 13, "connstby"); */ /* connected standby */
1716 /* ftcprint (features1, 14, "rapl"); */ /* running average power limit */
1719 if (orig_affinity_mask != 0)
1720 SetThreadGroupAffinity (GetCurrentThread (), &orig_group_affinity,
1721 NULL);
1722 print ("\n");
1725 print ("\n");
1727 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1728 memcpy (destbuf, buf, bufptr - buf);
1729 return bufptr - buf;
1732 static off_t
1733 format_proc_partitions (void *, char *&destbuf)
1735 OBJECT_ATTRIBUTES attr;
1736 IO_STATUS_BLOCK io;
1737 NTSTATUS status;
1738 HANDLE dirhdl;
1740 /* Open \Device object directory. */
1741 wchar_t wpath[MAX_PATH] = L"\\Device";
1742 UNICODE_STRING upath = {14, 16, wpath};
1743 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE, NULL, NULL);
1744 status = NtOpenDirectoryObject (&dirhdl, DIRECTORY_QUERY, &attr);
1745 if (!NT_SUCCESS (status))
1747 debug_printf ("NtOpenDirectoryObject, status %y", status);
1748 __seterrno_from_nt_status (status);
1749 return 0;
1752 tmp_pathbuf tp;
1753 char *buf = tp.c_get ();
1754 char *bufptr = buf;
1755 char *ioctl_buf = tp.c_get ();
1756 PWCHAR mp_buf = tp.w_get ();
1757 PDIRECTORY_BASIC_INFORMATION dbi_buf = (PDIRECTORY_BASIC_INFORMATION)
1758 tp.w_get ();
1759 WCHAR fpath[MAX_PATH];
1760 WCHAR gpath[MAX_PATH];
1761 DWORD len;
1763 /* Traverse \Device directory ... */
1764 BOOLEAN restart = TRUE;
1765 bool got_one = false;
1766 bool last_run = false;
1767 ULONG context = 0;
1768 while (!last_run)
1770 status = NtQueryDirectoryObject (dirhdl, dbi_buf, 65536, FALSE, restart,
1771 &context, NULL);
1772 if (!NT_SUCCESS (status))
1774 debug_printf ("NtQueryDirectoryObject, status %y", status);
1775 __seterrno_from_nt_status (status);
1776 break;
1778 if (status != STATUS_MORE_ENTRIES)
1779 last_run = true;
1780 restart = FALSE;
1781 for (PDIRECTORY_BASIC_INFORMATION dbi = dbi_buf;
1782 dbi->ObjectName.Length > 0;
1783 dbi++)
1785 HANDLE devhdl;
1786 PARTITION_INFORMATION_EX *pix = NULL;
1787 PARTITION_INFORMATION *pi = NULL;
1788 DWORD bytes_read;
1789 DWORD part_cnt = 0;
1790 unsigned long drive_num;
1791 unsigned long long size;
1793 /* ... and check for a "Harddisk[0-9]*" entry. */
1794 if (dbi->ObjectName.Length < 9 * sizeof (WCHAR)
1795 || wcsncasecmp (dbi->ObjectName.Buffer, L"Harddisk", 8) != 0
1796 || !iswdigit (dbi->ObjectName.Buffer[8]))
1797 continue;
1798 /* Got it. Now construct the path to the entire disk, which is
1799 "\\Device\\HarddiskX\\Partition0", and open the disk with
1800 minimum permissions. */
1801 drive_num = wcstoul (dbi->ObjectName.Buffer + 8, NULL, 10);
1802 wcscpy (wpath, dbi->ObjectName.Buffer);
1803 PWCHAR wpart = wpath + dbi->ObjectName.Length / sizeof (WCHAR);
1804 wcpcpy (wpart, L"\\Partition0");
1805 upath.Length = dbi->ObjectName.Length + 22;
1806 upath.MaximumLength = upath.Length + sizeof (WCHAR);
1807 InitializeObjectAttributes (&attr, &upath, OBJ_CASE_INSENSITIVE,
1808 dirhdl, NULL);
1809 status = NtOpenFile (&devhdl, READ_CONTROL, &attr, &io,
1810 FILE_SHARE_VALID_FLAGS, 0);
1811 if (!NT_SUCCESS (status))
1813 debug_printf ("NtOpenFile(%S), status %y", &upath, status);
1814 __seterrno_from_nt_status (status);
1815 continue;
1817 if (!got_one)
1819 print ("major minor #blocks name win-mounts\n\n");
1820 got_one = true;
1822 /* Fetch partition info for the entire disk to get its size. */
1823 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO_EX, NULL,
1824 0, ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1826 pix = (PARTITION_INFORMATION_EX *) ioctl_buf;
1827 size = pix->PartitionLength.QuadPart;
1829 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_PARTITION_INFO, NULL,
1830 0, ioctl_buf, NT_MAX_PATH, &bytes_read,
1831 NULL))
1833 pi = (PARTITION_INFORMATION *) ioctl_buf;
1834 size = pi->PartitionLength.QuadPart;
1836 else
1838 debug_printf ("DeviceIoControl (%S, "
1839 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath);
1840 size = 0;
1842 device dev (drive_num, 0);
1843 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s\n",
1844 dev.get_major (), dev.get_minor (),
1845 size >> 10, dev.name () + 5);
1846 /* Fetch drive layout info to get size of all partitions on disk. */
1847 if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT_EX, NULL, 0,
1848 ioctl_buf, NT_MAX_PATH, &bytes_read, NULL))
1850 PDRIVE_LAYOUT_INFORMATION_EX pdlix =
1851 (PDRIVE_LAYOUT_INFORMATION_EX) ioctl_buf;
1852 part_cnt = pdlix->PartitionCount;
1853 pix = pdlix->PartitionEntry;
1855 else if (DeviceIoControl (devhdl, IOCTL_DISK_GET_DRIVE_LAYOUT, NULL,
1856 0, ioctl_buf, NT_MAX_PATH, &bytes_read,
1857 NULL))
1859 PDRIVE_LAYOUT_INFORMATION pdli =
1860 (PDRIVE_LAYOUT_INFORMATION) ioctl_buf;
1861 part_cnt = pdli->PartitionCount;
1862 pi = pdli->PartitionEntry;
1864 else
1865 debug_printf ("DeviceIoControl(%S, "
1866 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath);
1867 /* Loop over partitions. */
1868 if (pix || pi)
1869 for (DWORD i = 0; i < part_cnt && i < 64; ++i)
1871 DWORD part_num;
1873 if (pix)
1875 size = pix->PartitionLength.QuadPart;
1876 part_num = pix->PartitionNumber;
1877 ++pix;
1879 else
1881 size = pi->PartitionLength.QuadPart;
1882 part_num = pi->PartitionNumber;
1883 ++pi;
1885 /* A partition number of 0 denotes an extended partition or a
1886 filler entry as described in
1887 fhandler_dev_floppy::lock_partition. Just skip. */
1888 if (part_num == 0)
1889 continue;
1890 device dev (drive_num, part_num);
1892 bufptr += __small_sprintf (bufptr, "%5d %5d %9U %s",
1893 dev.get_major (), dev.get_minor (),
1894 size >> 10, dev.name () + 5);
1895 /* Check if the partition is mounted in Windows and, if so,
1896 print the mount point list. */
1897 __small_swprintf (fpath,
1898 L"\\\\?\\GLOBALROOT\\Device\\%S\\Partition%u\\",
1899 &dbi->ObjectName, part_num);
1900 if (GetVolumeNameForVolumeMountPointW (fpath, gpath, MAX_PATH)
1901 && GetVolumePathNamesForVolumeNameW (gpath, mp_buf,
1902 NT_MAX_PATH, &len))
1904 len = strlen (dev.name () + 5);
1905 while (len++ < 6)
1906 *bufptr++ = ' ';
1907 for (PWCHAR p = mp_buf; *p; p = wcschr (p, L'\0') + 1)
1908 bufptr += __small_sprintf (bufptr, " %W", p);
1911 *bufptr++ = '\n';
1913 NtClose (devhdl);
1916 NtClose (dirhdl);
1918 if (!got_one)
1919 return 0;
1921 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1922 memcpy (destbuf, buf, bufptr - buf);
1923 return bufptr - buf;
1926 static off_t
1927 format_proc_self (void *, char *&destbuf)
1929 destbuf = (char *) crealloc_abort (destbuf, 16);
1930 return __small_sprintf (destbuf, "%d", getpid ());
1933 static off_t
1934 format_proc_cygdrive (void *, char *&destbuf)
1936 destbuf = (char *) crealloc_abort (destbuf, mount_table->cygdrive_len + 1);
1937 char *dend = stpcpy (destbuf, mount_table->cygdrive);
1938 if (dend > destbuf + 1) /* cygdrive != "/"? */
1939 *--dend = '\0';
1940 return dend - destbuf;
1943 static off_t
1944 format_proc_mounts (void *, char *&destbuf)
1946 destbuf = (char *) crealloc_abort (destbuf, sizeof ("self/mounts"));
1947 return __small_sprintf (destbuf, "self/mounts");
1950 static off_t
1951 format_proc_filesystems (void *, char *&destbuf)
1953 tmp_pathbuf tp;
1954 char *buf = tp.c_get ();
1955 char *bufptr = buf;
1957 /* start at 1 to skip type "none" */
1958 for (int i = 1; fs_names[i].name; i++)
1959 bufptr += __small_sprintf(bufptr, "%s\t%s\n",
1960 fs_names[i].block_device ? "" : "nodev",
1961 fs_names[i].name);
1963 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
1964 memcpy (destbuf, buf, bufptr - buf);
1965 return bufptr - buf;
1968 static off_t
1969 format_proc_swaps (void *, char *&destbuf)
1971 unsigned long long total = 0ULL, used = 0ULL;
1972 PSYSTEM_PAGEFILE_INFORMATION spi = NULL;
1973 ULONG size = 512;
1974 NTSTATUS status = STATUS_SUCCESS;
1976 tmp_pathbuf tp;
1977 char *buf = tp.c_get ();
1978 char *bufptr = buf;
1980 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1981 if (spi)
1983 status = NtQuerySystemInformation (SystemPagefileInformation, (PVOID) spi,
1984 size, &size);
1985 if (status == STATUS_INFO_LENGTH_MISMATCH)
1987 free (spi);
1988 spi = (PSYSTEM_PAGEFILE_INFORMATION) malloc (size);
1989 if (spi)
1990 status = NtQuerySystemInformation (SystemPagefileInformation,
1991 (PVOID) spi, size, &size);
1995 bufptr += __small_sprintf (bufptr,
1996 "Filename\t\t\t\tType\t\tSize\t\tUsed\t\tPriority\n");
1998 if (spi && NT_SUCCESS (status))
2000 PSYSTEM_PAGEFILE_INFORMATION spp = spi;
2001 char *filename = tp.c_get ();
2004 total = (unsigned long long) spp->CurrentSize * wincap.page_size ();
2005 used = (unsigned long long) spp->TotalUsed * wincap.page_size ();
2006 cygwin_conv_path (CCP_WIN_W_TO_POSIX, spp->FileName.Buffer,
2007 filename, NT_MAX_PATH);
2008 /* ensure space between fields for clarity */
2009 size_t tabo = strlen (filename) / 8; /* offset tabs to space name */
2010 bufptr += sprintf (bufptr, "%s%s%s\t\t%llu%s\t%llu%s\t%d\n",
2011 filename,
2012 tabo < 5 ? "\t\t\t\t\t" + tabo : " ",
2013 "file",
2014 total >> 10,
2015 total < 10000000000 ? "\t" : "",
2016 used >> 10,
2017 used < 10000000000 ? "\t" : "",
2020 while (spp->NextEntryOffset
2021 && (spp = (PSYSTEM_PAGEFILE_INFORMATION)
2022 ((char *) spp + spp->NextEntryOffset)));
2025 if (spi)
2026 free (spi);
2028 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
2029 memcpy (destbuf, buf, bufptr - buf);
2030 return bufptr - buf;
2033 static off_t
2034 format_proc_devices (void *, char *&destbuf)
2036 tmp_pathbuf tp;
2037 char *buf = tp.c_get ();
2038 char *bufptr = buf;
2040 bufptr += __small_sprintf (bufptr,
2041 "Character devices:\n"
2042 "%3d mem\n"
2043 "%3d cons\n"
2044 "%3d /dev/tty\n"
2045 "%3d /dev/console\n"
2046 "%3d /dev/ptmx\n"
2047 "%3d st\n"
2048 "%3d misc\n"
2049 "%3d sound\n"
2050 "%3d ttyS\n"
2051 "%3d tty\n"
2052 "\n"
2053 "Block devices:\n"
2054 "%3d fd\n"
2055 "%3d sd\n"
2056 "%3d sr\n"
2057 "%3d sd\n"
2058 "%3d sd\n"
2059 "%3d sd\n"
2060 "%3d sd\n"
2061 "%3d sd\n"
2062 "%3d sd\n"
2063 "%3d sd\n",
2064 DEV_MEM_MAJOR, DEV_CONS_MAJOR, _major (FH_TTY),
2065 _major (FH_CONSOLE), _major (FH_PTMX),
2066 DEV_TAPE_MAJOR, DEV_MISC_MAJOR, DEV_SOUND_MAJOR,
2067 DEV_SERIAL_MAJOR, DEV_PTYS_MAJOR, DEV_FLOPPY_MAJOR,
2068 DEV_SD_MAJOR, DEV_CDROM_MAJOR, DEV_SD1_MAJOR,
2069 DEV_SD2_MAJOR, DEV_SD3_MAJOR, DEV_SD4_MAJOR,
2070 DEV_SD5_MAJOR, DEV_SD6_MAJOR, DEV_SD7_MAJOR);
2072 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
2073 memcpy (destbuf, buf, bufptr - buf);
2074 return bufptr - buf;
2077 static off_t
2078 format_proc_misc (void *, char *&destbuf)
2080 tmp_pathbuf tp;
2081 char *buf = tp.c_get ();
2082 char *bufptr = buf;
2084 bufptr += __small_sprintf (bufptr,
2085 "%3d clipboard\n"
2086 "%3d windows\n",
2087 _minor (FH_CLIPBOARD), _minor (FH_WINDOWS));
2089 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
2090 memcpy (destbuf, buf, bufptr - buf);
2091 return bufptr - buf;
2094 static char *
2095 add_locale (char *bufptr, const char *posix_locale, const char *codeset,
2096 bool explicit_utf8, const char *modifier, const wchar_t *win_locale)
2098 const char *start = bufptr;
2099 bufptr = stpcpy (bufptr, posix_locale);
2100 if (explicit_utf8)
2101 bufptr = stpcpy (bufptr, ".utf8");
2102 if (modifier && modifier[0])
2103 bufptr = stpcpy (bufptr, modifier);
2104 if (bufptr - start < 16)
2106 if (bufptr - start < 8)
2107 bufptr = stpcpy (bufptr, "\t");
2108 bufptr = stpcpy (bufptr, "\t");
2110 bufptr = stpcpy (bufptr, "\t");
2111 start = bufptr;
2112 bufptr = stpcpy (bufptr, codeset);
2113 if (win_locale && win_locale[0])
2115 if (bufptr - start < 16)
2117 if (bufptr - start < 8)
2118 bufptr = stpcpy (bufptr, "\t");
2119 bufptr = stpcpy (bufptr, "\t");
2121 bufptr = stpcpy (bufptr, "\t");
2122 bufptr += wcstombs (bufptr, win_locale, wcslen (win_locale) * 2);
2124 bufptr = stpcpy (bufptr, "\n");
2125 return bufptr;
2128 static BOOL
2129 format_proc_locale_proc (LPWSTR win_locale, DWORD info, LPARAM param)
2131 char **bufptr_p = (char **) param;
2132 wchar_t iso15924_postfix[ENCODING_LEN + 1] = { 0 };
2133 wchar_t iso15924[ENCODING_LEN + 1] = { 0 };
2134 wchar_t iso3166[ENCODING_LEN + 1] = { 0 };
2135 wchar_t iso639[ENCODING_LEN + 1] = { 0 };
2136 wchar_t currency[9] = { 0 };
2137 char modifier[ENCODING_LEN + 1] = { 0 };
2138 char posix_loc[ENCODING_LEN + 1];
2139 char posix_loc_and_modifier[ENCODING_LEN + 1];
2140 char codeset[ENCODING_LEN + 1];
2141 wchar_t *cp;
2143 /* Skip language-only locales, e. g. "en" */
2144 if (!(cp = wcschr (win_locale, L'-')))
2145 return TRUE;
2146 ++cp;
2147 /* Script inside? Scripts are Upper/Lower, e. g. "Latn" */
2148 if (iswupper (cp[0]) && iswlower (cp[1]))
2150 wchar_t *cp2;
2152 /* Skip language-Script locales, missing country */
2153 if (!(cp2 = wcschr (cp + 2, L'-')))
2154 return TRUE;
2155 /* Otherwise, store in iso15924 */
2156 if (iso15924)
2157 wcpcpy (wcpncpy (iso15924, cp, cp2 - cp), L";");
2159 cp = wcsrchr (win_locale, L'-');
2160 if (cp)
2162 /* Skip numeric iso3166 country name. */
2163 if (iswdigit (cp[1]))
2164 return TRUE;
2165 /* Special case postfix after iso3166 country name: ca-ES-valencia.
2166 Use the postfix thingy as script so it will become a @modifier */
2167 if (iswlower (cp[1]))
2168 wcpcpy (iso15924_postfix, cp + 1);
2171 if (!GetLocaleInfoEx (win_locale, LOCALE_SISO639LANGNAME, iso639, 10))
2172 return TRUE;
2173 GetLocaleInfoEx (win_locale, LOCALE_SISO3166CTRYNAME, iso3166, 10);
2175 snprintf (posix_loc, sizeof posix_loc, "%.3ls_%.3ls", iso639, iso3166);
2176 /* Inuktitut: equivalent @latin due to lack of info on Linux */
2177 if (!wcscmp (iso639, L"iu"))
2179 if (wcscmp (iso15924, L"Latn;"))
2180 return TRUE;
2182 /* Javanese: only use @latin locale. */
2183 else if (!wcscmp (iso639, L"jv"))
2185 if (wcscmp (iso15924, L"Latn;"))
2186 return TRUE;
2188 /* Mongolian: only use @mongolian locale. */
2189 else if (!wcscmp (iso639, L"mn"))
2191 if (wcscmp (iso15924, L"Mong;"))
2192 return TRUE;
2194 /* Serbian: Windows default is Latin, Linux default is Cyrillic.
2195 We want the Linux default and attach @latin otherwise */
2196 else if (!wcscmp (iso639, L"sr"))
2198 snprintf (posix_loc, sizeof posix_loc, "sr_%.27ls", iso3166);
2199 if (!wcscmp (iso15924, L"Latn;"))
2200 stpcpy (modifier, "@latin");
2202 /* Tamazight: no modifier, iso639 is "ber" on Linux.
2203 "zgh-Tfng-MA" is equivalent to "ber_MA". */
2204 else if (!wcscmp (iso639, L"zgh"))
2205 snprintf (posix_loc, sizeof posix_loc, "ber_%.27ls", iso3166);
2206 /* Tamazight: "tzm-Latn-DZ" is equivalent to "ber_DZ",
2207 skip everything else. */
2208 else if (!wcscmp (iso639, L"tzm"))
2210 if (!wcscmp (iso3166, L"DZ") && !wcscmp (iso15924, L"Latn;"))
2211 snprintf (posix_loc, sizeof posix_loc, "ber_%.27ls", iso3166);
2212 else
2213 return TRUE;
2215 /* "sd-IN" is no valid Windows locale, only "sd-Deva-IN" is. However,
2216 asking for LOCALE_SSCRIPTS below returns "Arab;" because the first "sd"
2217 locale Windows finds is "sd-Arab-PK", so we have to override this here. */
2218 else if (!wcscmp (iso639, L"sd") && !wcscmp (iso3166, L"IN"))
2219 strcpy (posix_loc, "sd_IN");
2220 /* In all other cases, we check if the script from the Windows
2221 locale is the default locale in that language. If not, we
2222 add it as modifier if possible, or skip it */
2223 else if (iso15924[0])
2225 wchar_t scriptless_win_locale[ENCODING_LEN + 1];
2226 wchar_t default_iso15924[ENCODING_LEN + 1];
2228 wcpcpy (wcpcpy (wcpcpy (scriptless_win_locale, iso639), L"-"),
2229 iso3166);
2230 if ((GetLocaleInfoEx (scriptless_win_locale, LOCALE_SSCRIPTS,
2231 default_iso15924, ENCODING_LEN + 1)
2232 || GetLocaleInfoEx (iso639, LOCALE_SSCRIPTS,
2233 default_iso15924, ENCODING_LEN + 1))
2234 && !wcsstr (default_iso15924, iso15924))
2236 if (!wcscmp (iso15924, L"Latn;"))
2237 stpcpy (modifier, "@latin");
2238 else if (!wcscmp (iso15924, L"Cyrl;"))
2239 stpcpy (modifier, "@cyrillic");
2240 else if (!wcscmp (iso15924, L"Deva;"))
2241 stpcpy (modifier, "@devanagari");
2242 else if (!wcscmp (iso15924, L"Adlm;"))
2243 stpcpy (modifier, "@adlam");
2244 else
2245 return TRUE;
2248 else if (iso15924_postfix[0])
2250 modifier[0] = '@';
2251 wcstombs (modifier + 1, iso15924_postfix, 31);
2254 stpcpy (stpcpy (posix_loc_and_modifier, posix_loc), modifier);
2255 __set_charset_from_locale (posix_loc_and_modifier, codeset);
2256 *bufptr_p = add_locale (*bufptr_p, posix_loc, codeset, false, modifier,
2257 win_locale);
2258 if (strcmp (codeset, "UTF-8") != 0)
2259 *bufptr_p = add_locale (*bufptr_p, posix_loc, "UTF-8", true, modifier,
2260 win_locale);
2262 /* Only one cross each */
2263 if (modifier[0])
2264 return TRUE;
2266 /* Check for locales sporting an additional modifier for
2267 changing the codeset and other stuff. */
2268 if (!wcscmp (iso639, L"be") && !wcscmp (iso3166, L"BY"))
2269 stpcpy (modifier, "@latin");
2270 else if (!wcscmp (iso639, L"tt") && !wcscmp (iso3166, L"RU"))
2271 stpcpy (modifier, "@iqtelif");
2272 else if (!wcscmp (iso639, L"sd") && !wcscmp (iso3166, L"IN"))
2273 stpcpy (modifier, "@devanagari");
2274 /* If the base locale is ISO-8859-1 and the locale defines currency
2275 as EUR, add a @euro locale. For historical reasons there's also
2276 a greek @euro locale, albeit it doesn't change the codeset. */
2277 else if ((!strcmp (codeset, "ISO-8859-1")
2278 || !strcmp (posix_loc, "el_GR"))
2279 && GetLocaleInfoEx (win_locale, LOCALE_SINTLSYMBOL, currency, 9)
2280 && !wcsncmp (currency, L"EUR", 3))
2281 stpcpy (modifier, "@euro");
2282 else if (!wcscmp (iso639, L"ja")
2283 || !wcscmp (iso639, L"ko")
2284 || !wcscmp (iso639, L"zh"))
2285 stpcpy (modifier, "@cjknarrow");
2286 else
2287 return TRUE;
2289 stpcpy (stpcpy (posix_loc_and_modifier, posix_loc), modifier);
2290 __set_charset_from_locale (posix_loc_and_modifier, codeset);
2291 *bufptr_p = add_locale (*bufptr_p, posix_loc, codeset, false, modifier,
2292 win_locale);
2293 if (strcmp (codeset, "UTF-8") != 0 && strcmp (modifier, "@euro") != 0)
2294 *bufptr_p = add_locale (*bufptr_p, posix_loc, "UTF-8", true, modifier,
2295 win_locale);
2297 return TRUE;
2300 static off_t
2301 format_proc_locales (void *, char *&destbuf)
2303 tmp_pathbuf tp;
2304 char *buf = tp.t_get ();
2305 char *bufptr = buf;
2307 bufptr = stpcpy (bufptr, "Locale:\t\t\tCodeset:\t\tWindows-Locale:\n");
2308 bufptr = add_locale (bufptr, "C", "ANSI_X3.4-1968", false, NULL, NULL);
2309 bufptr = add_locale (bufptr, "C", "UTF-8", true, NULL, NULL);
2310 bufptr = add_locale (bufptr, "POSIX", "ANSI_X3.4-1968", false, NULL, NULL);
2312 EnumSystemLocalesEx (format_proc_locale_proc,
2313 LOCALE_WINDOWS | LOCALE_SUPPLEMENTAL,
2314 (LPARAM) &bufptr, NULL);
2316 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
2317 memcpy (destbuf, buf, bufptr - buf);
2318 return bufptr - buf;
2321 static off_t
2322 format_proc_codesets (void *, char *&destbuf)
2324 tmp_pathbuf tp;
2325 char *buf = tp.c_get ();
2326 char *bufptr = stpcpy (buf,
2327 "ASCII\n"
2328 "BIG5\n"
2329 "CP1125\n"
2330 "CP1250\n"
2331 "CP1251\n"
2332 "CP1252\n"
2333 "CP1253\n"
2334 "CP1254\n"
2335 "CP1255\n"
2336 "CP1256\n"
2337 "CP1257\n"
2338 "CP1258\n"
2339 "CP437\n"
2340 "CP720\n"
2341 "CP737\n"
2342 "CP775\n"
2343 "CP850\n"
2344 "CP852\n"
2345 "CP855\n"
2346 "CP857\n"
2347 "CP858\n"
2348 "CP862\n"
2349 "CP866\n"
2350 "CP874\n"
2351 "CP932\n"
2352 "EUC-CN\n"
2353 "EUC-JP\n"
2354 "EUC-KR\n"
2355 "GB18030\n"
2356 "GB2312\n"
2357 "GBK\n"
2358 "GEORGIAN-PS\n"
2359 "ISO-8859-1\n"
2360 "ISO-8859-10\n"
2361 "ISO-8859-11\n"
2362 "ISO-8859-13\n"
2363 "ISO-8859-14\n"
2364 "ISO-8859-15\n"
2365 "ISO-8859-16\n"
2366 "ISO-8859-2\n"
2367 "ISO-8859-3\n"
2368 "ISO-8859-4\n"
2369 "ISO-8859-5\n"
2370 "ISO-8859-6\n"
2371 "ISO-8859-7\n"
2372 "ISO-8859-8\n"
2373 "ISO-8859-9\n"
2374 "KOI8-R\n"
2375 "KOI8-T\n"
2376 "KOI8-U\n"
2377 "PT154\n"
2378 "SJIS\n"
2379 "TIS-620\n"
2380 "UTF-8\n");
2382 destbuf = (char *) crealloc_abort (destbuf, bufptr - buf);
2383 memcpy (destbuf, buf, bufptr - buf);
2384 return bufptr - buf;
2387 #undef print