]> git.ipfire.org Git - thirdparty/util-linux.git/blame - sys-utils/lscpu-dmi.c
sys-utils: cleanup license lines, add SPDX
[thirdparty/util-linux.git] / sys-utils / lscpu-dmi.c
CommitLineData
3cd676f5 1/*
9abd5e4b
KZ
2 * SPDX-License-Identifier: GPL-2.0
3 *
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.
7 *
3cd676f5
MM
8 * Copyright (C) 2020 FUJITSU LIMITED. All rights reserved.
9 */
3cd676f5
MM
10#include "lscpu.h"
11
12void to_dmi_header(struct lscpu_dmi_header *h, uint8_t *data)
13{
14 h->type = data[0];
15 h->length = data[1];
16 memcpy(&h->handle, data + 2, sizeof(h->handle));
17 h->data = data;
18}
19
20char *dmi_string(const struct lscpu_dmi_header *dm, uint8_t s)
21{
22 char *bp = (char *)dm->data;
23
24 if (!s || !bp)
25 return NULL;
26
27 bp += dm->length;
28 while (s > 1 && *bp) {
29 bp += strlen(bp);
30 bp++;
31 s--;
32 }
33
34 return !*bp ? NULL : bp;
35}
36
37int parse_dmi_table(uint16_t len, uint16_t num,
38 uint8_t *data,
39 struct dmi_info *di)
40{
41 uint8_t *buf = data;
42 int rc = -1;
43 int i = 0;
44
45 /* 4 is the length of an SMBIOS structure header */
46 while (i < num && data + 4 <= buf + len) {
47 uint8_t *next;
48 struct lscpu_dmi_header h;
49
50 to_dmi_header(&h, data);
51
52 /*
53 * If a short entry is found (less than 4 bytes), not only it
54 * is invalid, but we cannot reliably locate the next entry.
55 * Better stop at this point.
56 */
57 if (h.length < 4)
58 goto done;
59
60 /* look for the next handle */
61 next = data + h.length;
62 while (next - buf + 1 < len && (next[0] != 0 || next[1] != 0))
63 next++;
64 next += 2;
65 switch (h.type) {
66 case 0:
67 di->vendor = dmi_string(&h, data[0x04]);
68 break;
69 case 1:
70 di->manufacturer = dmi_string(&h, data[0x04]);
71 di->product = dmi_string(&h, data[0x05]);
72 break;
788f90d6 73 case 4:
a772d7c4
HS
74 /* Get the first processor information */
75 if (di->sockets == 0) {
76 di->processor_manufacturer = dmi_string(&h, data[0x7]);
77 di->processor_version = dmi_string(&h, data[0x10]);
78 di->current_speed = *((uint16_t *)(&data[0x16]));
79 di->part_num = dmi_string(&h, data[0x22]);
4cae2104
HS
80
81 if (data[0x6] == 0xfe)
82 di->processor_family = *((uint16_t *)(&data[0x28]));
83 else
84 di->processor_family = data[0x6];
a772d7c4 85 }
788f90d6
MM
86 di->sockets++;
87 break;
3cd676f5
MM
88 default:
89 break;
90 }
91
92 data = next;
93 i++;
94 }
95 rc = 0;
96done:
97 return rc;
98}
788f90d6 99
a772d7c4
HS
100int dmi_decode_cputype(struct lscpu_cputype *ct)
101{
102 static char const sys_fw_dmi_tables[] = _PATH_SYS_DMI;
103 struct dmi_info di = { };
104 struct stat st;
105 uint8_t *data;
106 int rc = 0;
107 char buf[100] = { };
108
109 if (stat(sys_fw_dmi_tables, &st))
110 return rc;
111
112 data = get_mem_chunk(0, st.st_size, sys_fw_dmi_tables);
113 if (!data)
114 return rc;
115
116 rc = parse_dmi_table(st.st_size, st.st_size/4, data, &di);
117 if (rc < 0) {
118 free(data);
119 return rc;
120 }
121
b366e69b
HS
122 if (di.processor_manufacturer)
123 ct->bios_vendor = xstrdup(di.processor_manufacturer);
a772d7c4 124
b366e69b
HS
125 snprintf(buf, sizeof(buf), "%s %s CPU @ %d.%dGHz",
126 (di.processor_version ?: ""), (di.part_num ?: ""),
a772d7c4
HS
127 di.current_speed/1000, (di.current_speed % 1000) / 100);
128 ct->bios_modelname = xstrdup(buf);
129
4cae2104
HS
130 /* Get CPU family */
131 memset(buf, 0, sizeof(buf));
132 snprintf(buf, sizeof(buf), "%d", di.processor_family);
133 ct->bios_family = xstrdup(buf);
134
a772d7c4
HS
135 free(data);
136 return 0;
137}
138
788f90d6
MM
139size_t get_number_of_physical_sockets_from_dmi(void)
140{
141 static char const sys_fw_dmi_tables[] = _PATH_SYS_DMI;
142 struct dmi_info di;
143 struct stat st;
144 uint8_t *data;
145 int rc = 0;
146
147 if (stat(sys_fw_dmi_tables, &st))
148 return rc;
149
150 data = get_mem_chunk(0, st.st_size, sys_fw_dmi_tables);
151 if (!data)
152 return rc;
153
154 memset(&di, 0, sizeof(struct dmi_info));
155 rc = parse_dmi_table(st.st_size, st.st_size/4, data, &di);
156
157 free(data);
158
159 if ((rc < 0) || !di.sockets)
160 return 0;
161 else
162 return di.sockets;
163}