4 * Copyright (C) 2010 IPFire. All rights reserved.
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
23 #include <linux/hdreg.h>
25 #include <sys/ioctl.h>
28 Big parts of this were taken from
29 http://git.kernel.org/?p=utils/util-linux-ng/util-linux-ng.git;a=blob;f=sys-utils/lscpu.c
33 #define _PATH_PROC_XEN "/proc/xen"
34 #define _PATH_PROC_XENCAP _PATH_PROC_XEN "/capabilities"
35 #define _PATH_PROC_PCIDEVS "/proc/bus/pci/devices"
37 /* Used for the vmware hypervisor port detection */
38 #define VMWARE_HYPERVISOR_MAGIC 0x564D5868
39 #define VMWARE_HYPERVISOR_PORT 0x5658
41 #define VMWARE_PORT_CMD_GETVERSION 10
43 #define VMWARE_PORT(cmd, eax, ebx, ecx, edx) \
44 __asm__("inl (%%dx)" : \
45 "=a"(eax), "=c"(ecx), "=d"(edx), "=b"(ebx) : \
46 "0"(VMWARE_HYPERVISOR_MAGIC), \
47 "1"(VMWARE_PORT_CMD_##cmd), \
48 "2"(VMWARE_HYPERVISOR_PORT), "3"(UINT_MAX) : \
51 /* virtualization types */
57 const char *virt_types
[] = {
63 /* hypervisor vendors */
71 const char *hv_vendors
[] = {
75 [HYPER_MSHV
] = "Microsoft",
76 [HYPER_VMWARE
] = "VMWare"
79 struct hypervisor_desc
{
80 int hyper
; /* hypervisor vendor ID */
81 int virtype
; /* VIRT_PARA|FULL|NONE ? */
84 static size_t sysrootlen
;
85 static char pathbuf
[PATH_MAX
];
87 static FILE *path_fopen(const char *mode
, const char *path
, ...)
88 __attribute__ ((__format__ (__printf__
, 2, 3)));
89 static int path_exist(const char *path
, ...)
90 __attribute__ ((__format__ (__printf__
, 1, 2)));
93 path_vcreate(const char *path
, va_list ap
)
96 vsnprintf(pathbuf
+ sysrootlen
,
97 sizeof(pathbuf
) - sysrootlen
, path
, ap
);
99 vsnprintf(pathbuf
, sizeof(pathbuf
), path
, ap
);
104 path_vfopen(const char *mode
, const char *path
, va_list ap
)
106 const char *p
= path_vcreate(path
, ap
);
108 return fopen(p
, mode
);
112 path_fopen(const char *mode
, const char *path
, ...)
118 fd
= path_vfopen(mode
, path
, ap
);
125 path_exist(const char *path
, ...)
131 p
= path_vcreate(path
, ap
);
134 return access(p
, F_OK
) == 0;
138 has_pci_device(int vendor
, int device
)
141 int num
, fn
, ven
, dev
;
144 f
= path_fopen("r", _PATH_PROC_PCIDEVS
);
148 /* for more details about bus/pci/devices format see
149 * drivers/pci/proc.c in linux kernel
151 while(fscanf(f
, "%02x%02x\t%04x%04x\t%*[^\n]",
152 &num
, &fn
, &ven
, &dev
) == 4) {
154 if (ven
== vendor
&& dev
== device
)
164 #if defined(__x86_64__) || defined(__i386__)
167 * This CPUID leaf returns the information about the hypervisor.
168 * EAX : maximum input value for CPUID supported by the hypervisor.
169 * EBX, ECX, EDX : Hypervisor vendor ID signature. E.g. VMwareVMware.
171 #define HYPERVISOR_INFO_LEAF 0x40000000
174 cpuid(unsigned int op
, unsigned int *eax
, unsigned int *ebx
,
175 unsigned int *ecx
, unsigned int *edx
)
178 #if defined(__PIC__) && defined(__i386__)
179 /* x86 PIC cannot clobber ebx -- gcc bitches */
196 read_hypervisor_cpuid(struct hypervisor_desc
*desc
)
198 unsigned int eax
= 0, ebx
= 0, ecx
= 0, edx
= 0;
199 char hyper_vendor_id
[13];
201 memset(hyper_vendor_id
, 0, sizeof(hyper_vendor_id
));
203 cpuid(HYPERVISOR_INFO_LEAF
, &eax
, &ebx
, &ecx
, &edx
);
204 memcpy(hyper_vendor_id
+ 0, &ebx
, 4);
205 memcpy(hyper_vendor_id
+ 4, &ecx
, 4);
206 memcpy(hyper_vendor_id
+ 8, &edx
, 4);
207 hyper_vendor_id
[12] = '\0';
209 if (!hyper_vendor_id
[0])
212 if (!strncmp("XenVMMXenVMM", hyper_vendor_id
, 12))
213 desc
->hyper
= HYPER_XEN
;
214 else if (!strncmp("KVMKVMKVM", hyper_vendor_id
, 9))
215 desc
->hyper
= HYPER_KVM
;
216 else if (!strncmp("Microsoft Hv", hyper_vendor_id
, 12))
217 desc
->hyper
= HYPER_MSHV
;
218 else if (!strncmp("VMwareVMware", hyper_vendor_id
, 12))
219 desc
->hyper
= HYPER_VMWARE
;
222 #else /* ! __x86_64__ */
224 read_hypervisor_cpuid(struct hypervisor_desc
*desc
)
230 read_hypervisor(struct hypervisor_desc
*desc
)
232 read_hypervisor_cpuid(desc
);
236 desc
->virtype
= VIRT_FULL
;
238 else if (path_exist(_PATH_PROC_XEN
)) {
239 /* Xen para-virt or dom0 */
240 FILE *fd
= path_fopen("r", _PATH_PROC_XENCAP
);
246 if (fscanf(fd
, "%s", buf
) == 1 &&
247 !strcmp(buf
, "control_d"))
251 desc
->virtype
= dom0
? VIRT_NONE
: VIRT_PARA
;
252 desc
->hyper
= HYPER_XEN
;
254 } else if (has_pci_device(0x5853, 0x0001)) {
255 /* Xen full-virt on non-x86_64 */
256 desc
->hyper
= HYPER_XEN
;
257 desc
->virtype
= VIRT_FULL
;
262 read_harddisk_serial(char *device
, char *serial
) {
263 static struct hd_driveid hd
;
266 if ((fd
= open(device
, O_RDONLY
| O_NONBLOCK
)) < 0) {
270 if (!ioctl(fd
, HDIO_GET_IDENTITY
, &hd
)) {
271 strncpy(serial
, (const char *)hd
.serial_no
, 20);
277 unsigned int eax
, ebx
, ecx
, edx
;
279 cpuid(0x1, &eax
, &ebx
, &ecx
, &edx
);
282 Bitwise detection of the 31st bit.
283 This indicates if a host runs in a virtual environment.
292 hypervisor_port_check(void) {
293 uint32_t eax
, ebx
, ecx
, edx
;
294 VMWARE_PORT(GETVERSION
, eax
, ebx
, ecx
, edx
);
295 if (ebx
== VMWARE_HYPERVISOR_MAGIC
)
296 return 1; // Success - running under VMware
302 do_get_hypervisor() {
304 Get hypervisor from the cpuid command.
306 struct hypervisor_desc _desc
, *desc
= &_desc
;
307 memset(desc
, 0, sizeof(*desc
));
309 read_hypervisor(desc
);
311 PyObject
*d
= PyDict_New();
315 if (desc
->hyper
== HYPER_NONE
) {
318 o
= PyString_FromString((const char *)hv_vendors
[desc
->hyper
]);
320 PyDict_SetItemString(d
, "hypervisor", o
);
322 /* Virtualization type */
323 if (desc
->virtype
== VIRT_NONE
) {
326 o
= PyString_FromString((const char *)virt_types
[desc
->virtype
]);
328 PyDict_SetItemString(d
, "virtype", o
);
334 do_is_virtualized() {
336 Python wrapper around is_virtualized().
339 if (is_virtualized())
346 do_get_harddisk_serial(PyObject
*o
, PyObject
*args
) {
348 Python wrapper around read_harddisk_serial.
352 memset(serial
, 0, sizeof(serial
));
355 if (!PyArg_ParseTuple(args
, "s", &device
))
358 read_harddisk_serial(device
, serial
);
361 return PyString_FromString(serial
);
367 do_hypervisor_port_check() {
369 Python wrapper around hypervisor_port_check().
372 if (hypervisor_port_check())
378 static PyMethodDef fireinfoModuleMethods
[] = {
379 { "get_hypervisor", (PyCFunction
) do_get_hypervisor
, METH_NOARGS
, NULL
},
380 { "is_virtualized", (PyCFunction
) do_is_virtualized
, METH_NOARGS
, NULL
},
381 { "get_harddisk_serial", (PyCFunction
) do_get_harddisk_serial
, METH_VARARGS
, NULL
},
382 { "vmware_hypervisor_port_check", (PyCFunction
) do_hypervisor_port_check
, METH_NOARGS
, NULL
},
383 { NULL
, NULL
, 0, NULL
}
386 void init_fireinfo(void) {
389 m
= Py_InitModule("_fireinfo", fireinfoModuleMethods
);