1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <sys/stat.h>
4 #ifndef WIN32
5 #include <unistd.h>
6 #endif
7 
8 #include <string.h>
9 #include "hardware.h"
10 
11 #define PLL_FEAT_AVAIL(x,y) (((x) & (y)) == (y))
12 #define PLL_SYS_CPU_DIR_PATH "/sys/devices/system/cpu/"
13 
14 //#ifdef _MSC_VER
15 //#define inline __inline
16 //#endif
17 
cpuid(unsigned int op,int count,unsigned int * eax,unsigned int * ebx,unsigned int * ecx,unsigned int * edx)18 static __inline void cpuid(unsigned int op, int count,
19                          unsigned int *eax, unsigned int *ebx,
20                          unsigned int *ecx, unsigned int *edx)
21 {
22 #ifdef WIN32
23 	__int32 regs[4];
24 	__cpuid((int*)regs, (int)op);
25 	*eax = regs[0];
26 	*ebx = regs[1];
27 	*ecx = regs[2];
28 	*edx = regs[3];
29 #else
30 	*eax = op;
31   *ecx = count;
32   asm volatile("cpuid"
33         : "=a" (*eax),
34           "=b" (*ebx),
35           "=c" (*ecx),
36           "=d" (*edx)
37 
38         : "0" (*eax), "2" (*ecx)
39         : "memory");
40 #endif
41 }
42 
43 
show_hardware_info(pllHardwareInfo * hw)44 void show_hardware_info(pllHardwareInfo * hw)
45 {
46   printf ("MMX.........: %d\n"
47           "SSE.........: %d\n"
48           "SSE2........: %d\n"
49           "SSE3........: %d\n"
50           "SSSE3.......: %d\n"
51           "FMA.........: %d\n"
52           "SSE4.1......: %d\n"
53           "SSE4.2......: %d\n"
54           "AVX.........: %d\n"
55           "AVX2........: %d\n"
56           "SSE4A.......: %d\n"
57           "FMA4........: %d\n\n"
58           "Core(s).....: %d\n"
59           "CPU Sockets.: %d\n",
60 
61           hw->has_mmx, hw->has_sse, hw->has_sse2, hw->has_sse3, hw->has_ssse3,
62           hw->has_fma, hw->has_sse41, hw->has_sse42, hw->has_avx, hw->has_avx2,
63           hw->has_sse4a, hw->has_fma4, hw->cores, hw->cpu_sockets);
64 }
65 
pll_probe_cpu(pllHardwareInfo * hw)66 static int pll_probe_cpu (pllHardwareInfo * hw)
67 {
68   struct stat cpustat;
69   char cpu[30];
70   char cpupath[100];
71   int i, id, max_physical_id = -1;
72   char * physical_id_path = "/topology/physical_package_id";
73   FILE * fd;
74 
75   /* check whether the sys cpu dir exists */
76   if (stat(PLL_SYS_CPU_DIR_PATH, &cpustat)) return (0);
77 
78   /* and also check whether it is a dir */
79   if (!S_ISDIR(cpustat.st_mode)) return (0);
80 
81   /* detect number of processors */
82   for (i = 0; ; ++i)
83    {
84      sprintf(cpu, "cpu%d", i);
85      strcpy (cpupath, PLL_SYS_CPU_DIR_PATH);
86      strcat (cpupath, cpu);
87      if (stat(cpupath, &cpustat)) break;
88 
89      strcat (cpupath, physical_id_path);
90      if (!stat(cpupath, &cpustat))
91       {
92         fd = fopen (cpupath,"r");
93         fscanf (fd, "%d", &id);
94         /* printf ("Detected processor %d belonging to package %d\n", i, id); */
95         if (id > max_physical_id) max_physical_id = id;
96         fclose (fd);
97       }
98    }
99 
100   hw->cores       = i;
101   hw->cpu_sockets = max_physical_id + 1;
102 
103   return (1);
104 }
105 
pll_probe_hardware(pllHardwareInfo * hw)106 static void pll_probe_hardware (pllHardwareInfo * hw)
107 {
108   unsigned int a, b, c, d;
109   c = 0;
110 
111   cpuid(0,0,&a,&b,&c,&d);
112   *((unsigned int *)(hw->vendor)    ) = b;
113   *((unsigned int *)(hw->vendor + 4)) = d;
114   *((unsigned int *)(hw->vendor + 8)) = c;
115   hw->vendor[12] = 0;
116 
117   printf ("%s\n", hw->vendor);
118 
119   cpuid(1,0,&a,&b,&c,&d);
120 
121   hw->has_mmx   = PLL_FEAT_AVAIL(d,PLL_HAS_MMX);
122   hw->has_sse   = PLL_FEAT_AVAIL(d,PLL_HAS_SSE);
123   hw->has_sse2  = PLL_FEAT_AVAIL(d,PLL_HAS_SSE2);
124 
125   hw->has_sse3  = PLL_FEAT_AVAIL(c,PLL_HAS_SSE3);
126   hw->has_ssse3 = PLL_FEAT_AVAIL(c,PLL_HAS_SSSE3);
127   hw->has_fma   = PLL_FEAT_AVAIL(c,PLL_HAS_FMA);
128   hw->has_sse41 = PLL_FEAT_AVAIL(c,PLL_HAS_SSE41);
129   hw->has_sse42 = PLL_FEAT_AVAIL(c,PLL_HAS_SSE42);
130   hw->has_avx   = PLL_FEAT_AVAIL(c,PLL_HAS_AVX);
131 
132   cpuid(7,0,&a,&b,&c,&d);
133 
134   hw->has_avx2  = PLL_FEAT_AVAIL(b,PLL_HAS_AVX2);
135 
136   /* TODO: note, here we have to check whether leaf 0x80000001 exists */
137   cpuid(0x80000001,0,&a,&b,&c,&d);
138 
139   hw->has_sse4a = PLL_FEAT_AVAIL(c,PLL_HAS_SSE4A);
140   hw->has_fma4  = PLL_FEAT_AVAIL(c,PLL_HAS_FMA4);
141 }
142 
pllGetHardwareInfo(pllHardwareInfo * hw)143 int pllGetHardwareInfo (pllHardwareInfo * hw)
144 {
145   pll_probe_hardware (hw);
146   pll_probe_cpu (hw);
147 
148   /* TODO: finish failure checks in probe_hardware and probe_cpu */
149   return (1);
150 
151 }
152 
153 /* TODO: Remove after testing */
154 /*
155 int main (int argc, char * argv[])
156 {
157   pllHardwareInfo hw;
158 
159   pll_probe_hardware(&hw);
160   pll_probe_cpu(&hw);
161 
162   show_hardware_info(&hw);
163   return (EXIT_SUCCESS);
164 }
165 */
166