]>
git.ipfire.org Git - thirdparty/util-linux.git/blob - sys-utils/lscpu-dmi.c
2 * lscpu-dmi - Module to parse SMBIOS information
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation; either version 2 of the License, or
7 * (at your option) any later version.
9 * This program is distributed in the hope that it would be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License along
15 * with this program; if not, write to the Free Software Foundation, Inc.,
16 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
18 * Code originally taken from the dmidecode utility and slightly rewritten
19 * to suite the needs of lscpu
23 #include <sys/types.h>
32 #define _PATH_SYS_DMI "/sys/firmware/dmi/tables/DMI"
34 #define WORD(x) (uint16_t)(*(const uint16_t *)(x))
35 #define DWORD(x) (uint32_t)(*(const uint32_t *)(x))
45 static void *get_mem_chunk(size_t base
, size_t len
, const char *devmem
)
50 if ((fd
= open(devmem
, O_RDONLY
)) < 0)
53 if (!(p
= malloc(len
)))
55 if (lseek(fd
, base
, SEEK_SET
) == -1)
57 if (read_all(fd
, p
, len
) == -1)
69 static void to_dmi_header(struct dmi_header
*h
, uint8_t *data
)
73 memcpy(&h
->handle
, data
+ 2, sizeof(h
->handle
));
77 static char *dmi_string(const struct dmi_header
*dm
, uint8_t s
)
79 char *bp
= (char *)dm
->data
;
98 static int hypervisor_from_dmi_table(uint32_t base
, uint16_t len
,
99 uint16_t num
, const char *devmem
)
105 char *product
= NULL
;
106 char *manufacturer
= NULL
;
109 data
= buf
= get_mem_chunk(base
, len
, devmem
);
113 /* 4 is the length of an SMBIOS structure header */
114 while (i
< num
&& data
+ 4 <= buf
+ len
) {
118 to_dmi_header(&h
, data
);
121 * If a short entry is found (less than 4 bytes), not only it
122 * is invalid, but we cannot reliably locate the next entry.
123 * Better stop at this point.
128 /* look for the next handle */
129 next
= data
+ h
.length
;
130 while (next
- buf
+ 1 < len
&& (next
[0] != 0 || next
[1] != 0))
135 vendor
= dmi_string(&h
, data
[0x04]);
138 manufacturer
= dmi_string(&h
, data
[0x04]);
139 product
= dmi_string(&h
, data
[0x05]);
148 if (manufacturer
&& !strcmp(manufacturer
, "innotek GmbH"))
150 else if (manufacturer
&& strstr(manufacturer
, "HITACHI") &&
151 product
&& strstr(product
, "LPAR"))
153 else if (vendor
&& !strcmp(vendor
, "Parallels"))
154 rc
= HYPER_PARALLELS
;
160 static int checksum(const uint8_t *buf
, size_t len
)
165 for (a
= 0; a
< len
; a
++)
170 #if defined(__x86_64__) || defined(__i386__)
171 static int hypervisor_decode_legacy(uint8_t *buf
, const char *devmem
)
173 if (!checksum(buf
, 0x0F))
176 return hypervisor_from_dmi_table(DWORD(buf
+ 0x08), WORD(buf
+ 0x06),
182 static int hypervisor_decode_smbios(uint8_t *buf
, const char *devmem
)
184 if (!checksum(buf
, buf
[0x05])
185 || memcmp(buf
+ 0x10, "_DMI_", 5) != 0
186 || !checksum(buf
+ 0x10, 0x0F))
189 return hypervisor_from_dmi_table(DWORD(buf
+ 0x18), WORD(buf
+ 0x16),
195 * Probe for EFI interface
197 #define EFI_NOT_FOUND (-1)
198 #define EFI_NO_SMBIOS (-2)
199 static int address_from_efi(size_t *address
)
205 *address
= 0; /* Prevent compiler warning */
208 * Linux up to 2.6.6: /proc/efi/systab
209 * Linux 2.6.7 and up: /sys/firmware/efi/systab
211 if (!(tab
= fopen("/sys/firmware/efi/systab", "r")) &&
212 !(tab
= fopen("/proc/efi/systab", "r")))
213 return EFI_NOT_FOUND
; /* No EFI interface */
216 while ((fgets(linebuf
, sizeof(linebuf
) - 1, tab
)) != NULL
) {
217 char *addrp
= strchr(linebuf
, '=');
221 if (strcmp(linebuf
, "SMBIOS") == 0) {
222 *address
= strtoul(addrp
, NULL
, 0);
232 static int read_hypervisor_dmi_from_devmem(void)
238 /* First try EFI (ia64, Intel-based Mac) */
239 switch (address_from_efi(&fp
)) {
246 buf
= get_mem_chunk(fp
, 0x20, _PATH_DEV_MEM
);
250 rc
= hypervisor_decode_smbios(buf
, _PATH_DEV_MEM
);
251 if (rc
>= HYPER_NONE
)
257 #if defined(__x86_64__) || defined(__i386__)
258 /* Fallback to memory scan (x86, x86_64) */
259 buf
= get_mem_chunk(0xF0000, 0x10000, _PATH_DEV_MEM
);
263 for (fp
= 0; fp
<= 0xFFF0; fp
+= 16) {
264 if (memcmp(buf
+ fp
, "_SM_", 4) == 0 && fp
<= 0xFFE0) {
265 rc
= hypervisor_decode_smbios(buf
+ fp
, _PATH_DEV_MEM
);
269 } else if (memcmp(buf
+ fp
, "_DMI_", 5) == 0)
270 rc
= hypervisor_decode_legacy(buf
+ fp
, _PATH_DEV_MEM
);
272 if (rc
>= HYPER_NONE
)
281 static int read_hypervisor_dmi_from_sysfw(void)
283 static char const sys_fw_dmi_tables
[] = _PATH_SYS_DMI
;
286 if (stat(sys_fw_dmi_tables
, &st
))
289 return hypervisor_from_dmi_table(0, st
.st_size
, st
.st_size
/ 4,
293 int read_hypervisor_dmi(void)
297 if (sizeof(uint8_t) != 1
298 || sizeof(uint16_t) != 2
299 || sizeof(uint32_t) != 4
303 /* -1 : no DMI in /sys,
304 * 0 : DMI exist, nothing detected (HYPER_NONE)
305 * >0 : hypervisor detected
307 rc
= read_hypervisor_dmi_from_sysfw();
309 rc
= read_hypervisor_dmi_from_devmem();
311 return rc
< 0 ? HYPER_NONE
: rc
;