3 * Copyright (C) 2010, 2011 IPFire Team (www.ipfire.org)
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 3 of the License, or
8 * (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with this program. If not, see <http://www.gnu.org/licenses/>.
22 #include <linux/hdreg.h>
24 #include <sys/ioctl.h>
27 Big parts of this were taken from
28 http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blob;f=sys-utils/lscpu.c
32 #define _PATH_PROC_XEN "/proc/xen"
33 #define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
34 #define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
36 /* Used for the vmware hypervisor port detection */
37 #define VMWARE_HYPERVISOR_MAGIC 0x564D5868
38 #define VMWARE_HYPERVISOR_PORT 0x5658
40 #define VMWARE_PORT_CMD_GETVERSION 10
42 /* virtualization types */
48 const char *virt_types
[] = {
54 /* hypervisor vendors */
62 const char *hv_vendors
[] = {
66 [HYPER_MSHV
] = "Microsoft",
67 [HYPER_VMWARE
] = "VMWare"
70 struct hypervisor_desc
{
71 int hyper
; /* hypervisor vendor ID */
72 int virtype
; /* VIRT_PARA|FULL|NONE ? */
75 static size_t sysrootlen
;
76 static char pathbuf
[PATH_MAX
];
78 static FILE *path_fopen(const char *mode
, const char *path
, ...)
79 __attribute__ ((__format__ (__printf__
, 2, 3)));
80 static int path_exist(const char *path
, ...)
81 __attribute__ ((__format__ (__printf__
, 1, 2)));
84 path_vcreate(const char *path
, va_list ap
)
87 vsnprintf(pathbuf
+ sysrootlen
,
88 sizeof(pathbuf
) - sysrootlen
, path
, ap
);
90 vsnprintf(pathbuf
, sizeof(pathbuf
), path
, ap
);
95 path_vfopen(const char *mode
, const char *path
, va_list ap
)
97 const char *p
= path_vcreate(path
, ap
);
99 return fopen(p
, mode
);
103 path_fopen(const char *mode
, const char *path
, ...)
109 fd
= path_vfopen(mode
, path
, ap
);
116 path_exist(const char *path
, ...)
122 p
= path_vcreate(path
, ap
);
125 return access(p
, F_OK
) == 0;
129 has_pci_device(int vendor
, int device
)
132 int num
, fn
, ven
, dev
;
135 f
= path_fopen("r", _PATH_PROC_PCIDEVS
);
139 /* for more details about bus/pci/devices format see
140 * drivers/pci/proc.c in linux kernel
142 while(fscanf(f
, "%02x%02x\t%04x%04x\t%*[^\n]",
143 &num
, &fn
, &ven
, &dev
) == 4) {
145 if (ven
== vendor
&& dev
== device
)
155 #if defined(__x86_64__) || defined(__i386__)
158 * This CPUID leaf returns the information about the hypervisor.
159 * EAX : maximum input value for CPUID supported by the hypervisor.
160 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
162 #define HYPERVISOR_INFO_LEAF 0x40000000
165 cpuid(unsigned int op
, unsigned int *eax
, unsigned int *ebx
,
166 unsigned int *ecx
, unsigned int *edx
)
169 #if defined(__PIC__) && defined(__i386__)
170 /* x86 PIC cannot clobber ebx -- gcc bitches */
187 read_hypervisor_cpuid(struct hypervisor_desc
*desc
)
189 unsigned int eax
= 0, ebx
= 0, ecx
= 0, edx
= 0;
190 char hyper_vendor_id
[13];
192 memset(hyper_vendor_id
, 0, sizeof(hyper_vendor_id
));
194 cpuid(HYPERVISOR_INFO_LEAF
, &eax
, &ebx
, &ecx
, &edx
);
195 memcpy(hyper_vendor_id
+ 0, &ebx
, 4);
196 memcpy(hyper_vendor_id
+ 4, &ecx
, 4);
197 memcpy(hyper_vendor_id
+ 8, &edx
, 4);
198 hyper_vendor_id
[12] = '\0';
200 if (!hyper_vendor_id
[0])
203 if (!strncmp("XenVMMXenVMM", hyper_vendor_id
, 12))
204 desc
->hyper
= HYPER_XEN
;
205 else if (!strncmp("KVMKVMKVM", hyper_vendor_id
, 9))
206 desc
->hyper
= HYPER_KVM
;
207 else if (!strncmp("Microsoft Hv", hyper_vendor_id
, 12))
208 desc
->hyper
= HYPER_MSHV
;
209 else if (!strncmp("VMwareVMware", hyper_vendor_id
, 12))
210 desc
->hyper
= HYPER_VMWARE
;
213 #else /* ! __x86_64__ */
215 read_hypervisor_cpuid(struct hypervisor_desc
*desc
)
221 read_hypervisor(struct hypervisor_desc
*desc
)
223 read_hypervisor_cpuid(desc
);
227 desc
->virtype
= VIRT_FULL
;
229 else if (path_exist(_PATH_PROC_XEN
)) {
230 /* Xen para-virt or dom0 */
231 FILE *fd
= path_fopen("r", _PATH_PROC_XENCAP
);
237 if (fscanf(fd
, "%s", buf
) == 1 &&
238 !strcmp(buf
, "control_d"))
242 desc
->virtype
= dom0
? VIRT_NONE
: VIRT_PARA
;
243 desc
->hyper
= HYPER_XEN
;
245 } else if (has_pci_device(0x5853, 0x0001)) {
246 /* Xen full-virt on non-x86_64 */
247 desc
->hyper
= HYPER_XEN
;
248 desc
->virtype
= VIRT_FULL
;
253 read_harddisk_serial(char *device
, char *serial
) {
254 static struct hd_driveid hd
;
257 if ((fd
= open(device
, O_RDONLY
| O_NONBLOCK
)) < 0) {
261 if (!ioctl(fd
, HDIO_GET_IDENTITY
, &hd
)) {
262 strncpy(serial
, (const char *)hd
.serial_no
, 20);
268 unsigned int eax
, ebx
, ecx
, edx
;
270 cpuid(0x1, &eax
, &ebx
, &ecx
, &edx
);
273 Bitwise detection of the 31st bit.
274 This indicates if a host runs in a virtual environment.
283 hypervisor_port(unsigned int cmd
, unsigned int *eax
, unsigned int *ebx
,
284 unsigned int *ecx
, unsigned int *edx
)
287 #if defined(__PIC__) && defined(__i386__)
288 /* x86 PIC really cannot clobber ebx */
301 : "0" (VMWARE_HYPERVISOR_MAGIC
),
303 "2" (VMWARE_HYPERVISOR_PORT
),
310 hypervisor_port_check(void) {
311 uint32_t eax
, ebx
, ecx
, edx
;
313 hypervisor_port(VMWARE_PORT_CMD_GETVERSION
, &eax
, &ebx
, &ecx
, &edx
);
315 if (ebx
== VMWARE_HYPERVISOR_MAGIC
)
316 return 1; // Success - running under VMware
322 do_get_hypervisor() {
324 Get hypervisor from the cpuid command.
326 struct hypervisor_desc _desc
, *desc
= &_desc
;
327 memset(desc
, 0, sizeof(*desc
));
329 read_hypervisor(desc
);
331 PyObject
*d
= PyDict_New();
335 if (desc
->hyper
== HYPER_NONE
) {
338 o
= PyString_FromString((const char *)hv_vendors
[desc
->hyper
]);
340 PyDict_SetItemString(d
, "hypervisor", o
);
342 /* Virtualization type */
343 if (desc
->virtype
== VIRT_NONE
) {
346 o
= PyString_FromString((const char *)virt_types
[desc
->virtype
]);
348 PyDict_SetItemString(d
, "virtype", o
);
354 do_is_virtualized() {
356 Python wrapper around is_virtualized().
359 if (is_virtualized())
366 do_get_harddisk_serial(PyObject
*o
, PyObject
*args
) {
368 Python wrapper around read_harddisk_serial.
372 memset(serial
, 0, sizeof(serial
));
375 if (!PyArg_ParseTuple(args
, "s", &device
))
378 read_harddisk_serial(device
, serial
);
381 return PyString_FromString(serial
);
387 do_hypervisor_port_check() {
389 Python wrapper around hypervisor_port_check().
392 if (hypervisor_port_check())
398 static PyMethodDef fireinfoModuleMethods
[] = {
399 { "get_hypervisor", (PyCFunction
) do_get_hypervisor
, METH_NOARGS
, NULL
},
400 { "is_virtualized", (PyCFunction
) do_is_virtualized
, METH_NOARGS
, NULL
},
401 { "get_harddisk_serial", (PyCFunction
) do_get_harddisk_serial
, METH_VARARGS
, NULL
},
402 { "vmware_hypervisor_port_check", (PyCFunction
) do_hypervisor_port_check
, METH_NOARGS
, NULL
},
403 { NULL
, NULL
, 0, NULL
}
406 void init_fireinfo(void) {
409 m
= Py_InitModule("_fireinfo", fireinfoModuleMethods
);