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