]>
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 int checksum(const uint8_t *buf
, size_t len
)
50 for (a
= 0; a
< len
; a
++)
55 static void *get_mem_chunk(size_t base
, size_t len
, const char *devmem
)
60 if ((fd
= open(devmem
, O_RDONLY
)) < 0)
63 if (!(p
= malloc(len
)))
65 if (lseek(fd
, base
, SEEK_SET
) == -1)
67 if (read_all(fd
, p
, len
) == -1)
79 static void to_dmi_header(struct dmi_header
*h
, uint8_t *data
)
83 h
->handle
= WORD(data
+ 2);
87 static char *dmi_string(const struct dmi_header
*dm
, uint8_t s
)
89 char *bp
= (char *)dm
->data
;
108 static int hypervisor_from_dmi_table(uint32_t base
, uint16_t len
,
109 uint16_t num
, const char *devmem
)
115 char *product
= NULL
;
116 char *manufacturer
= NULL
;
119 data
= buf
= get_mem_chunk(base
, len
, devmem
);
123 /* 4 is the length of an SMBIOS structure header */
124 while (i
< num
&& data
+ 4 <= buf
+ len
) {
128 to_dmi_header(&h
, data
);
131 * If a short entry is found (less than 4 bytes), not only it
132 * is invalid, but we cannot reliably locate the next entry.
133 * Better stop at this point.
138 /* look for the next handle */
139 next
= data
+ h
.length
;
140 while (next
- buf
+ 1 < len
&& (next
[0] != 0 || next
[1] != 0))
145 vendor
= dmi_string(&h
, data
[0x04]);
148 manufacturer
= dmi_string(&h
, data
[0x04]);
149 product
= dmi_string(&h
, data
[0x05]);
158 if (manufacturer
&& !strcmp(manufacturer
, "innotek GmbH"))
160 else if (manufacturer
&& strstr(manufacturer
, "HITACHI") &&
161 product
&& strstr(product
, "LPAR"))
163 else if (vendor
&& !strcmp(vendor
, "Parallels"))
164 rc
= HYPER_PARALLELS
;
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),
194 static int hypervisor_decode_sysfw(void)
196 static char const sys_fw_dmi_tables
[] = _PATH_SYS_DMI
;
199 if (stat(sys_fw_dmi_tables
, &st
))
202 return hypervisor_from_dmi_table(0, st
.st_size
, st
.st_size
/ 4,
207 * Probe for EFI interface
209 #define EFI_NOT_FOUND (-1)
210 #define EFI_NO_SMBIOS (-2)
211 static int address_from_efi(size_t *address
)
217 *address
= 0; /* Prevent compiler warning */
220 * Linux up to 2.6.6: /proc/efi/systab
221 * Linux 2.6.7 and up: /sys/firmware/efi/systab
223 if (!(tab
= fopen("/sys/firmware/efi/systab", "r")) &&
224 !(tab
= fopen("/proc/efi/systab", "r")))
225 return EFI_NOT_FOUND
; /* No EFI interface */
228 while ((fgets(linebuf
, sizeof(linebuf
) - 1, tab
)) != NULL
) {
229 char *addrp
= strchr(linebuf
, '=');
233 if (strcmp(linebuf
, "SMBIOS") == 0) {
234 *address
= strtoul(addrp
, NULL
, 0);
244 int read_hypervisor_dmi(void)
250 if (sizeof(uint8_t) != 1
251 || sizeof(uint16_t) != 2
252 || sizeof(uint32_t) != 4
256 /* -1 : no DMI in /sys,
257 * 0 : DMI exist, nothing detected (HYPER_NONE)
258 * >0 : hypervisor detected
260 rc
= hypervisor_decode_sysfw();
261 if (rc
>= HYPER_NONE
)
264 /* First try EFI (ia64, Intel-based Mac) */
265 switch (address_from_efi(&fp
)) {
272 buf
= get_mem_chunk(fp
, 0x20, _PATH_DEV_MEM
);
276 rc
= hypervisor_decode_smbios(buf
, _PATH_DEV_MEM
);
277 if (rc
>= HYPER_NONE
)
283 #if defined(__x86_64__) || defined(__i386__)
284 /* Fallback to memory scan (x86, x86_64) */
285 buf
= get_mem_chunk(0xF0000, 0x10000, _PATH_DEV_MEM
);
289 for (fp
= 0; fp
<= 0xFFF0; fp
+= 16) {
290 if (memcmp(buf
+ fp
, "_SM_", 4) == 0 && fp
<= 0xFFE0) {
291 rc
= hypervisor_decode_smbios(buf
+ fp
, _PATH_DEV_MEM
);
295 } else if (memcmp(buf
+ fp
, "_DMI_", 5) == 0)
296 rc
= hypervisor_decode_legacy(buf
+ fp
, _PATH_DEV_MEM
);
298 if (rc
>= HYPER_NONE
)
304 return rc
< 0 ? HYPER_NONE
: rc
;