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
10 #include "miscfuncs.h"
18 #include "shared_info.h"
20 #include "fhandler_virtual.h"
25 #include <sys/utsname.h>
26 #include <sys/param.h>
27 #include <sys/sysinfo.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. */
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
] != '/')
104 /* Helper function to perform a binary search of the incoming pathname
105 against the alpha-sorted virtual file table. */
107 virt_tab_search (const char *path
, bool prefix
, const virt_tab_t
*table
,
110 virt_tab_t key
= { path
, 0, FH_NADA
, virt_none
, NULL
};
111 virt_tab_t
*entry
= (virt_tab_t
*) bsearch (&key
, table
, nelem
,
114 if (entry
&& (path
[entry
->name_len
] == '\0'
115 || (prefix
&& path
[entry
->name_len
] == '/')))
120 /* Auxillary function that returns the fhandler associated with the given
123 fhandler_proc::get_proc_fhandler (const char *path
)
125 debug_printf ("get_proc_fhandler(%s)", path
);
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
130 while (isdirsep (*path
))
133 /* Check if this is the root of the virtual filesystem (i.e. /proc). */
137 virt_tab_t
*entry
= virt_tab_search (path
, true, proc_tab
,
140 return entry
->fhandler
;
143 pid_t pid
= strtoul (path
, &e
, 10);
144 if (*e
!= '/' && *e
!= '\0')
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')
159 bool has_subdir
= false;
161 if (isdirsep (*path
++))
168 /* The user is trying to access a non-existent subdirectory of /proc. */
171 /* Return FH_PROC so that we can return EROFS if the user is trying to
177 fhandler_proc::exists ()
179 const char *path
= get_name ();
180 debug_printf ("exists (%s)", path
);
184 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
188 fileid
= entry
- proc_tab
;
194 fhandler_proc::fhandler_proc ():
200 fhandler_proc::fstat (struct stat
*buf
)
202 const char *path
= get_name ();
203 debug_printf ("fstat (%s)", path
);
206 fhandler_base::fstat (buf
);
208 buf
->st_mode
&= ~_IFMT
& NO_W
;
212 winpids
pids ((DWORD
) 0);
214 buf
->st_mode
|= S_IFDIR
| S_IXUSR
| S_IXGRP
| S_IXOTH
;
215 buf
->st_nlink
= PROC_DIR_COUNT
+ 2 + pids
.npids
;
220 virt_tab_t
*entry
= virt_tab_search (path
+ 1, false, proc_tab
,
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
;
230 buf
->st_mode
&= NO_X
;
231 buf
->st_mode
|= S_IFREG
;
241 fhandler_proc::opendir (int fd
)
243 DIR *dir
= fhandler_virtual::opendir (fd
);
244 if (dir
&& !(dir
->__handle
= (void *) new winpids ((DWORD
) 0)))
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
)
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
);
269 dir
->__flags
|= dirent_saw_dot
| dirent_saw_dot_dot
;
274 winpids
&pids
= *(winpids
*) dir
->__handle
;
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
);
288 syscall_printf ("%d = readdir(%p, %p) (%s)", res
, dir
, de
, de
->d_name
);
293 fhandler_proc::open (int flags
, mode_t mode
)
295 int proc_file_no
= -1;
297 int res
= fhandler_virtual::open (flags
, mode
);
305 path
= get_name () + proc_len
;
309 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
315 else if (flags
& O_WRONLY
)
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
),
334 if (proc_tab
[i
].fhandler
!= FH_PROC
)
336 if ((flags
& (O_CREAT
| O_EXCL
)) == (O_CREAT
| O_EXCL
))
342 else if (flags
& O_WRONLY
)
356 if (proc_file_no
== -1)
371 if (flags
& O_WRONLY
)
378 fileid
= proc_file_no
;
379 if (!fill_filebuf ())
385 if (flags
& O_APPEND
)
392 set_flags ((flags
& ~O_TEXT
) | O_BINARY
);
395 syscall_printf ("%d = fhandler_proc::open(%y, 0%o)", res
, flags
, mode
);
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
);
411 extern "C" int uname_x (struct utsname
*);
414 format_proc_version (void *, char *&destbuf
)
417 char *buf
= tp
.c_get ();
419 struct utsname 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
);
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
)) {
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
);
460 format_proc_meminfo (void *, char *&destbuf
)
462 unsigned long long mem_total
, mem_free
, swap_total
, swap_free
;
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"
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);
486 format_proc_uptime (void *, char *&destbuf
)
488 unsigned long long uptime
= 0ULL, idle_time
= 0ULL;
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
)
499 status
= NtQuerySystemInformation (SystemTimeOfDayInformation
, &stodi
,
501 if (NT_SUCCESS (status
))
502 uptime
= (stodi
.CurrentTime
.QuadPart
- stodi
.BootTime
.QuadPart
) / 100000ULL;
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 ())
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));
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;
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
)
532 SYSTEM_TIMEOFDAY_INFORMATION stodi
;
535 char *buf
= tp
.c_get ();
538 SYSTEM_PROCESSOR_PERFORMANCE_INFORMATION spt
[wincap
.cpu_count ()];
539 status
= NtQuerySystemInformation (SystemProcessorPerformanceInformation
,
541 sizeof spt
[0] * wincap
.cpu_count (), NULL
);
542 if (!NT_SUCCESS (status
))
543 debug_printf ("NtQuerySystemInformation(SystemProcessorPerformanceInformation), "
544 "status %y", status
);
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
);
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"
611 destbuf
= (char *) crealloc_abort (destbuf
, eobuf
- buf
);
612 memcpy (destbuf
, buf
, 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;
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
;
644 const int BUFSIZE
= 256;
649 WCHAR w
[BUFSIZE
/ sizeof (WCHAR
)];
655 char *buf
= tp
.c_get ();
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
)))
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
= {
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
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 },
699 { NULL
, RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_NOSTRING
,
700 L
"Update Signature", &uc
[1], REG_NONE
, NULL
, 0 },
702 { NULL
, RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_NOSTRING
,
703 L
"CurrentPatchLevel", &uc
[2], REG_NONE
, NULL
, 0 },
705 { NULL
, RTL_QUERY_REGISTRY_DIRECT
| RTL_QUERY_REGISTRY_NOSTRING
,
706 L
"Platform Specific Field1", &uc
[3], REG_NONE
, NULL
, 0 },
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
,
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 (µcode
, 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);
743 /* Vendor identification. */
744 bool is_amd
= false, is_intel
= false;
745 if (!strcmp ((char*)vendor_id
, "AuthenticAMD")
746 || !strcmp((char*)vendor_id
, "HygonGenuine"))
748 else if (!strcmp ((char*)vendor_id
, "GenuineIntel"))
751 bufptr
+= __small_sprintf (bufptr
, "vendor_id\t: %s\n",
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;
761 family
+= (cpuid_sig
>> 20) & 0xff;
763 model
|= ((cpuid_sig
>> 16) & 0x0f) << 4; /* ext model << 4 | model */
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);
779 /* Could implement a lookup table here if someone needs it. */
780 strcpy (in_buf
.s
, "unknown");
784 cache_alignment
= 64;
785 long (*get_cpu_cache
) (int, uint32_t) = NULL
;
787 if (features1
& (1 << 19)) /* CLFSH */
788 clflush
= ((extra_info
>> 8) & 0xff) << 3;
789 if (is_intel
&& family
== 15)
790 cache_alignment
= clflush
* 2;
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 */
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 */
807 cs
= get_cpu_cache (_SC_LEVEL3_CACHE_SIZE
, max
);
809 cs
= get_cpu_cache (_SC_LEVEL2_CACHE_SIZE
, max
);
812 cs
= get_cpu_cache (_SC_LEVEL1_ICACHE_SIZE
, max
);
815 cs
= get_cpu_cache (_SC_LEVEL1_DCACHE_SIZE
, max
);
824 bufptr
+= __small_sprintf (bufptr
, "cpu family\t: %d\n"
828 "microcode\t: 0x%X\n"
829 "cpu MHz\t\t: %d.000\n",
832 in_buf
.s
+ strspn (in_buf
.s
, " \t"),
838 bufptr
+= __small_sprintf (bufptr
, "cache size\t: %d KB\n",
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. */
856 if (maxf
>= 0x0000000b) /* topoext supported? */
858 uint32_t bits
, logical
, level
, unused
;
861 cpuid (&bits
, &logical
, &level
, &unused
,
863 /* Even if topoext is supposedly supported, it can return
865 if (bits
!= 0 && ((level
>> 8) & 0xff) == 1)
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
,
876 uint32_t level_type
= ((level
>> 8) & 0xff);
877 if (level_type
== 0) /* Invalid */
879 if (level_type
== 2) /* Core */
881 logical_bits
= (bits
& 0x1f);
882 siblings
= (logical
& 0xffff);
883 cpu_cores
= siblings
>> ht_bits
;
889 if (!valid
&& maxf
>= 0x00000004)
891 uint32_t apic_reserved
;
893 cpuid (&apic_reserved
, &unused
, &unused
, &unused
,
895 if (apic_reserved
& 0x1f)
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
);
907 logical_bits
= mask_bits (siblings
);
908 ht_bits
= mask_bits (siblings
/ cpu_cores
);
912 if (!valid
) /* single core, multi thread */
915 siblings
= (extra_info
>> 16) & 0xff;
916 logical_bits
= mask_bits (siblings
);
917 ht_bits
= logical_bits
;
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)
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;
942 logical_bits
= mask_bits (siblings
);
947 siblings
= (extra_info
>> 16) & 0xff;
948 cpu_cores
= siblings
;
949 logical_bits
= mask_bits (siblings
);
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"
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
);
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"
975 bufptr
+= __small_sprintf (bufptr
, "apicid\t\t: %d\n"
976 "initial apicid\t: %d\n",
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
)
986 cpuid (&a
, &b
, &c
, &d
, l
);
987 if (!(a
| b
| c
| d
)) --level
;
990 for (uint32_t l
= maxf
; 1 < l
; --l
)
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"
1001 (features1
& (1 << 0)) ? "yes" : "no",
1002 (features1
& (1 << 0)) ? "yes" : "no",
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);
1069 /* cpuid 0x80000007 edx */
1070 if (maxe
>= 0x80000007)
1071 cpuid (&unused
, &unused
, &unused
, &features2
, 0x80000007);
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);
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);
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 */
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)
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 */
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)
1197 /* Denverton don't report hz nor support cpuid 0x16 so set 25MHz */
1198 if (kHz
== 0 && model
== 0x5F) /* Atom Goldmont D Denverton */
1201 /* cpuid TSC frequency is known */
1203 ftuprint ("tsc_known_freq"); /* TSC has known frequency */
1204 #if 0 /* keep for future and doc */
1206 /* Skylake and Kabylake don't report clock so use CPU speed and ratio */
1207 if (maxf
>= 0x00000016)
1210 cpuid(&mHz
, &unused
, &unused
, &unused
, 0x00000016);
1211 kHz
= mHz
* 1000 * cr_num
/ cr_den
;
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 */
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 */
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)
1295 case 0x57: /* Xeon Phi Knights Landing */
1296 case 0x85: /* Xeon Phi Knights Mill */
1297 ftuprint ("ring3mwait"); /* Ring 3 MONITOR/MWAIT instructions */
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); */
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); */
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)
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 */
1662 bufptr
+= __small_sprintf (bufptr
, "bogomips\t: %d.00\n",
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);
1671 bufptr
+= __small_sprintf (bufptr
, "TLB size\t: %d 4K pages\n",
1675 bufptr
+= __small_sprintf (bufptr
, "clflush size\t: %d\n"
1676 "cache_alignment\t: %d\n",
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)
1690 bufptr
+= __small_sprintf (bufptr
, "address sizes\t: "
1691 "%u bits physical, "
1692 "%u bits virtual\n",
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
,
1727 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1728 memcpy (destbuf
, buf
, bufptr
- buf
);
1729 return bufptr
- buf
;
1733 format_proc_partitions (void *, char *&destbuf
)
1735 OBJECT_ATTRIBUTES attr
;
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
);
1753 char *buf
= tp
.c_get ();
1755 char *ioctl_buf
= tp
.c_get ();
1756 PWCHAR mp_buf
= tp
.w_get ();
1757 PDIRECTORY_BASIC_INFORMATION dbi_buf
= (PDIRECTORY_BASIC_INFORMATION
)
1759 WCHAR fpath
[MAX_PATH
];
1760 WCHAR gpath
[MAX_PATH
];
1763 /* Traverse \Device directory ... */
1764 BOOLEAN restart
= TRUE
;
1765 bool got_one
= false;
1766 bool last_run
= false;
1770 status
= NtQueryDirectoryObject (dirhdl
, dbi_buf
, 65536, FALSE
, restart
,
1772 if (!NT_SUCCESS (status
))
1774 debug_printf ("NtQueryDirectoryObject, status %y", status
);
1775 __seterrno_from_nt_status (status
);
1778 if (status
!= STATUS_MORE_ENTRIES
)
1781 for (PDIRECTORY_BASIC_INFORMATION dbi
= dbi_buf
;
1782 dbi
->ObjectName
.Length
> 0;
1786 PARTITION_INFORMATION_EX
*pix
= NULL
;
1787 PARTITION_INFORMATION
*pi
= NULL
;
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]))
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
,
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
);
1819 print ("major minor #blocks name win-mounts\n\n");
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
,
1833 pi
= (PARTITION_INFORMATION
*) ioctl_buf
;
1834 size
= pi
->PartitionLength
.QuadPart
;
1838 debug_printf ("DeviceIoControl (%S, "
1839 "IOCTL_DISK_GET_PARTITION_INFO{_EX}) %E", &upath
);
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
,
1859 PDRIVE_LAYOUT_INFORMATION pdli
=
1860 (PDRIVE_LAYOUT_INFORMATION
) ioctl_buf
;
1861 part_cnt
= pdli
->PartitionCount
;
1862 pi
= pdli
->PartitionEntry
;
1865 debug_printf ("DeviceIoControl(%S, "
1866 "IOCTL_DISK_GET_DRIVE_LAYOUT{_EX}): %E", &upath
);
1867 /* Loop over partitions. */
1869 for (DWORD i
= 0; i
< part_cnt
&& i
< 64; ++i
)
1875 size
= pix
->PartitionLength
.QuadPart
;
1876 part_num
= pix
->PartitionNumber
;
1881 size
= pi
->PartitionLength
.QuadPart
;
1882 part_num
= pi
->PartitionNumber
;
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. */
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
,
1904 len
= strlen (dev
.name () + 5);
1907 for (PWCHAR p
= mp_buf
; *p
; p
= wcschr (p
, L
'\0') + 1)
1908 bufptr
+= __small_sprintf (bufptr
, " %W", p
);
1921 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1922 memcpy (destbuf
, buf
, bufptr
- buf
);
1923 return bufptr
- buf
;
1927 format_proc_self (void *, char *&destbuf
)
1929 destbuf
= (char *) crealloc_abort (destbuf
, 16);
1930 return __small_sprintf (destbuf
, "%d", getpid ());
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 != "/"? */
1940 return dend
- destbuf
;
1944 format_proc_mounts (void *, char *&destbuf
)
1946 destbuf
= (char *) crealloc_abort (destbuf
, sizeof ("self/mounts"));
1947 return __small_sprintf (destbuf
, "self/mounts");
1951 format_proc_filesystems (void *, char *&destbuf
)
1954 char *buf
= tp
.c_get ();
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",
1963 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
1964 memcpy (destbuf
, buf
, bufptr
- buf
);
1965 return bufptr
- buf
;
1969 format_proc_swaps (void *, char *&destbuf
)
1971 unsigned long long total
= 0ULL, used
= 0ULL;
1972 PSYSTEM_PAGEFILE_INFORMATION spi
= NULL
;
1974 NTSTATUS status
= STATUS_SUCCESS
;
1977 char *buf
= tp
.c_get ();
1980 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
1983 status
= NtQuerySystemInformation (SystemPagefileInformation
, (PVOID
) spi
,
1985 if (status
== STATUS_INFO_LENGTH_MISMATCH
)
1988 spi
= (PSYSTEM_PAGEFILE_INFORMATION
) malloc (size
);
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",
2012 tabo
< 5 ? "\t\t\t\t\t" + tabo
: " ",
2015 total
< 10000000000 ? "\t" : "",
2017 used
< 10000000000 ? "\t" : "",
2020 while (spp
->NextEntryOffset
2021 && (spp
= (PSYSTEM_PAGEFILE_INFORMATION
)
2022 ((char *) spp
+ spp
->NextEntryOffset
)));
2028 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
2029 memcpy (destbuf
, buf
, bufptr
- buf
);
2030 return bufptr
- buf
;
2034 format_proc_devices (void *, char *&destbuf
)
2037 char *buf
= tp
.c_get ();
2040 bufptr
+= __small_sprintf (bufptr
,
2041 "Character devices:\n"
2045 "%3d /dev/console\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
;
2078 format_proc_misc (void *, char *&destbuf
)
2081 char *buf
= tp
.c_get ();
2084 bufptr
+= __small_sprintf (bufptr
,
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
;
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
);
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");
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");
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];
2143 /* Skip language-only locales, e. g. "en" */
2144 if (!(cp
= wcschr (win_locale
, L
'-')))
2147 /* Script inside? Scripts are Upper/Lower, e. g. "Latn" */
2148 if (iswupper (cp
[0]) && iswlower (cp
[1]))
2152 /* Skip language-Script locales, missing country */
2153 if (!(cp2
= wcschr (cp
+ 2, L
'-')))
2155 /* Otherwise, store in iso15924 */
2157 wcpcpy (wcpncpy (iso15924
, cp
, cp2
- cp
), L
";");
2159 cp
= wcsrchr (win_locale
, L
'-');
2162 /* Skip numeric iso3166 country name. */
2163 if (iswdigit (cp
[1]))
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))
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;"))
2182 /* Javanese: only use @latin locale. */
2183 else if (!wcscmp (iso639
, L
"jv"))
2185 if (wcscmp (iso15924
, L
"Latn;"))
2188 /* Mongolian: only use @mongolian locale. */
2189 else if (!wcscmp (iso639
, L
"mn"))
2191 if (wcscmp (iso15924
, L
"Mong;"))
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
);
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
"-"),
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");
2248 else if (iso15924_postfix
[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
,
2258 if (strcmp (codeset
, "UTF-8") != 0)
2259 *bufptr_p
= add_locale (*bufptr_p
, posix_loc
, "UTF-8", true, modifier
,
2262 /* Only one cross each */
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");
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
,
2293 if (strcmp (codeset
, "UTF-8") != 0 && strcmp (modifier
, "@euro") != 0)
2294 *bufptr_p
= add_locale (*bufptr_p
, posix_loc
, "UTF-8", true, modifier
,
2301 format_proc_locales (void *, char *&destbuf
)
2304 char *buf
= tp
.t_get ();
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
;
2322 format_proc_codesets (void *, char *&destbuf
)
2325 char *buf
= tp
.c_get ();
2326 char *bufptr
= stpcpy (buf
,
2382 destbuf
= (char *) crealloc_abort (destbuf
, bufptr
- buf
);
2383 memcpy (destbuf
, buf
, bufptr
- buf
);
2384 return bufptr
- buf
;