1 /*
2  * This file and its contents are supplied under the terms of the
3  * Common Development and Distribution License ("CDDL"), version 1.0.
4  * You may only use this file in accordance with the terms of version
5  * 1.0 of the CDDL.
6  *
7  * A full copy of the text of the CDDL should have accompanied this
8  * source.  A copy of the CDDL is also available via the Internet at
9  * http://www.illumos.org/license/CDDL.
10  */
11 
12 /*
13  * Copyright 2019 Robert Mustacchi
14  */
15 
16 /*
17  * Basic testing of the SMBIOS 3.3 memory device extensions. We test these in a
18  * few different ways:
19  *
20  * 1. Using a 3.2 table with a 3.2 library to make sure we get the old fields.
21  * We also need to verify that we don't clobber memory in this case.
22  * 2. Using a 3.2 table with a 3.3 library to make sure we get the new fields.
23  * populated with the corresponding 3.2 values.
24  * 3. Using a 3.3 table with only the old values as valid.
25  * 4. Using a 3.3 table with both the old and new values as valid.
26  * memory.
27  */
28 
29 #include <stdlib.h>
30 #include "smbios_test.h"
31 
32 static uint16_t smbios_memdevice_speed = 0xdeed;
33 static uint16_t smbios_memdevice_clkspeed = 0xf00f;
34 static uint32_t smbios_memdevice_extspeed = 0xbaddeed;
35 static uint32_t smbios_memdevice_extclkspeed = 0xbadf00f;
36 
37 /*
38  * Fill in the basics of a single memory device. Callers need to fill in the
39  * speed, extspeed, clkspeed, and extclkspeed members.
40  */
41 static void
smbios_test_memdevice_fill(smb_memdevice_t * mem)42 smbios_test_memdevice_fill(smb_memdevice_t *mem)
43 {
44 	mem->smbmdev_hdr.smbh_type = SMB_TYPE_MEMDEVICE;
45 	mem->smbmdev_hdr.smbh_len = sizeof (smb_memdevice_t);
46 
47 	mem->smbmdev_array = 0xffff;
48 	mem->smbmdev_error = htole16(0xfffe);
49 	mem->smbmdev_twidth = 64;
50 	mem->smbmdev_dwidth = 64;
51 	mem->smbmdev_size = 0x7fff;
52 	mem->smbmdev_form = SMB_MDFF_FBDIMM;
53 	mem->smbmdev_set = 0;
54 	mem->smbmdev_dloc = 0;
55 	mem->smbmdev_bloc = 0;
56 	mem->smbmdev_type = SMB_MDT_DDR4;
57 	mem->smbmdev_manufacturer = 0;
58 	mem->smbmdev_asset = 0;
59 	mem->smbmdev_part = 0;
60 	mem->smbmdev_attrs = 2;
61 	mem->smbmdev_extsize = htole32(0x123456);
62 	mem->smbmdev_minvolt = 0;
63 	mem->smbmdev_maxvolt = 0;
64 	mem->smbmdev_confvolt = 0;
65 	mem->smbmdev_memtech = 0;
66 	mem->smbmdev_opmode = 1 << 3;
67 	mem->smbmdev_fwver = 0;
68 	mem->smbmdev_modulemfgid = 0;
69 	mem->smbmdev_moduleprodid = 0;
70 	mem->smbmdev_memsysmfgid = 0;
71 	mem->smbmdev_memsysprodid = 0;
72 	mem->smbmdev_nvsize = htole64(UINT64_MAX);
73 	mem->smbmdev_volsize = htole64(UINT64_MAX);
74 	mem->smbmdev_cachesize = htole64(UINT64_MAX);
75 	mem->smbmdev_logicalsize = htole64(UINT64_MAX);
76 }
77 
78 boolean_t
smbios_test_memdevice_mktable_32(smbios_test_table_t * table)79 smbios_test_memdevice_mktable_32(smbios_test_table_t *table)
80 {
81 	smb_memdevice_t mem;
82 	size_t len = 0x54;
83 
84 	smbios_test_memdevice_fill(&mem);
85 	mem.smbmdev_speed = htole16(smbios_memdevice_speed);
86 	mem.smbmdev_clkspeed = htole16(smbios_memdevice_clkspeed);
87 	mem.smbmdev_extspeed = htole32(0);
88 	mem.smbmdev_extclkspeed = htole32(0);
89 
90 	/*
91 	 * Because we're emulating an SMBIOS 3.2 table, we have to set it to the
92 	 * specification's defined size for that revision - 0x54.
93 	 */
94 	mem.smbmdev_hdr.smbh_len = len;
95 	(void) smbios_test_table_append(table, &mem, len);
96 	smbios_test_table_append_eot(table);
97 
98 	return (B_TRUE);
99 }
100 
101 boolean_t
smbios_test_memdevice_mktable_33(smbios_test_table_t * table)102 smbios_test_memdevice_mktable_33(smbios_test_table_t *table)
103 {
104 	smb_memdevice_t mem;
105 
106 	smbios_test_memdevice_fill(&mem);
107 	mem.smbmdev_speed = htole16(smbios_memdevice_speed);
108 	mem.smbmdev_clkspeed = htole16(smbios_memdevice_clkspeed);
109 	mem.smbmdev_extspeed = htole32(0);
110 	mem.smbmdev_extclkspeed = htole32(0);
111 
112 	(void) smbios_test_table_append(table, &mem, sizeof (mem));
113 	smbios_test_table_append_eot(table);
114 
115 	return (B_TRUE);
116 }
117 
118 boolean_t
smbios_test_memdevice_mktable_33ext(smbios_test_table_t * table)119 smbios_test_memdevice_mktable_33ext(smbios_test_table_t *table)
120 {
121 	smb_memdevice_t mem;
122 
123 	smbios_test_memdevice_fill(&mem);
124 	mem.smbmdev_speed = htole16(0xffff);
125 	mem.smbmdev_clkspeed = htole16(0xffff);
126 	mem.smbmdev_extspeed = htole32(smbios_memdevice_extspeed);
127 	mem.smbmdev_extclkspeed = htole32(smbios_memdevice_extclkspeed);
128 
129 	(void) smbios_test_table_append(table, &mem, sizeof (mem));
130 	smbios_test_table_append_eot(table);
131 
132 	return (B_TRUE);
133 }
134 
135 static boolean_t
smbios_test_memdevice_verify_common(smbios_memdevice_t * mem)136 smbios_test_memdevice_verify_common(smbios_memdevice_t *mem)
137 {
138 	boolean_t ret = B_TRUE;
139 
140 	if (mem->smbmd_dwidth != 64) {
141 		warnx("found wrong dwidth: %u", mem->smbmd_dwidth);
142 		ret = B_FALSE;
143 	}
144 
145 	if (mem->smbmd_twidth != 64) {
146 		warnx("found wrong twidth: %u", mem->smbmd_twidth);
147 		ret = B_FALSE;
148 	}
149 
150 	if (mem->smbmd_form != SMB_MDFF_FBDIMM) {
151 		warnx("found wrong form: %u", mem->smbmd_form);
152 		ret = B_FALSE;
153 	}
154 
155 	if (mem->smbmd_size != 0x123456ULL * 1024 * 1024) {
156 		warnx("found wrong size: %u", mem->smbmd_size);
157 		ret = B_FALSE;
158 	}
159 
160 	return (ret);
161 }
162 
163 boolean_t
smbios_test_memdevice_verify_32(smbios_hdl_t * hdl)164 smbios_test_memdevice_verify_32(smbios_hdl_t *hdl)
165 {
166 	smbios_struct_t sp;
167 	smbios_memdevice_t mem;
168 	boolean_t ret = B_TRUE;
169 	uint64_t rval;
170 
171 	/*
172 	 * We expect that the SMBIOS 3.2 memory device values should not be
173 	 * touched here. As such we set them to a random value to verify and
174 	 * verify that it hasn't been set.
175 	 */
176 	arc4random_buf(&rval, sizeof (rval));
177 	mem.smbmd_extspeed = rval;
178 	mem.smbmd_extclkspeed = rval;
179 
180 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
181 		warnx("failed to lookup SMBIOS memory device: %s",
182 		    smbios_errmsg(smbios_errno(hdl)));
183 		return (B_FALSE);
184 	}
185 
186 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
187 		warnx("failed to get SMBIOS memory device info: %s",
188 		    smbios_errmsg(smbios_errno(hdl)));
189 		return (B_FALSE);
190 	}
191 
192 	if (mem.smbmd_extspeed != rval || mem.smbmd_extclkspeed != rval) {
193 		warnx("smbios_memdevice_t had its memory cloberred!");
194 		return (B_FALSE);
195 	}
196 
197 	if (!smbios_test_memdevice_verify_common(&mem)) {
198 		return (B_FALSE);
199 	}
200 
201 	if (mem.smbmd_speed != smbios_memdevice_speed) {
202 		warnx("found wrong device speed: %u", mem.smbmd_speed);
203 		ret = B_FALSE;
204 	}
205 
206 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
207 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
208 		ret = B_FALSE;
209 	}
210 
211 	return (ret);
212 }
213 
214 /*
215  * This is a variant of smbios_test_memdevice_verify_32(), but instead of using
216  * an SMBIOS 3.2 library, we use an SMBIOS 3.3 handle. This means that we expect
217  * the extended values to be populated with the base values.
218  */
219 boolean_t
smbios_test_memdevice_verify_32_33(smbios_hdl_t * hdl)220 smbios_test_memdevice_verify_32_33(smbios_hdl_t *hdl)
221 {
222 	smbios_struct_t sp;
223 	smbios_memdevice_t mem;
224 	boolean_t ret = B_TRUE;
225 
226 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
227 		warnx("failed to lookup SMBIOS memory device: %s",
228 		    smbios_errmsg(smbios_errno(hdl)));
229 		return (B_FALSE);
230 	}
231 
232 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
233 		warnx("failed to get SMBIOS memory device info: %s",
234 		    smbios_errmsg(smbios_errno(hdl)));
235 		return (B_FALSE);
236 	}
237 
238 	if (!smbios_test_memdevice_verify_common(&mem)) {
239 		return (B_FALSE);
240 	}
241 
242 	if (mem.smbmd_speed != smbios_memdevice_speed) {
243 		warnx("found wrong device speed: %u", mem.smbmd_speed);
244 		ret = B_FALSE;
245 	}
246 
247 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
248 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
249 		ret = B_FALSE;
250 	}
251 
252 	if (mem.smbmd_extspeed != smbios_memdevice_speed) {
253 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
254 		ret = B_FALSE;
255 	}
256 
257 	if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
258 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
259 		ret = B_FALSE;
260 	}
261 
262 	return (ret);
263 }
264 
265 boolean_t
smbios_test_memdevice_verify_33(smbios_hdl_t * hdl)266 smbios_test_memdevice_verify_33(smbios_hdl_t *hdl)
267 {
268 	smbios_struct_t sp;
269 	smbios_memdevice_t mem;
270 	boolean_t ret = B_TRUE;
271 
272 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
273 		warnx("failed to lookup SMBIOS memory device: %s",
274 		    smbios_errmsg(smbios_errno(hdl)));
275 		return (B_FALSE);
276 	}
277 
278 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
279 		warnx("failed to get SMBIOS memory device info: %s",
280 		    smbios_errmsg(smbios_errno(hdl)));
281 		return (B_FALSE);
282 	}
283 
284 	if (!smbios_test_memdevice_verify_common(&mem)) {
285 		return (B_FALSE);
286 	}
287 
288 	if (mem.smbmd_speed != smbios_memdevice_speed) {
289 		warnx("found wrong device speed: %u", mem.smbmd_speed);
290 		ret = B_FALSE;
291 	}
292 
293 	if (mem.smbmd_clkspeed != smbios_memdevice_clkspeed) {
294 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
295 		ret = B_FALSE;
296 	}
297 
298 	if (mem.smbmd_extspeed != smbios_memdevice_speed) {
299 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
300 		ret = B_FALSE;
301 	}
302 
303 	if (mem.smbmd_extclkspeed != smbios_memdevice_clkspeed) {
304 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
305 		ret = B_FALSE;
306 	}
307 
308 	return (ret);
309 }
310 
311 boolean_t
smbios_test_memdevice_verify_33ext(smbios_hdl_t * hdl)312 smbios_test_memdevice_verify_33ext(smbios_hdl_t *hdl)
313 {
314 	smbios_struct_t sp;
315 	smbios_memdevice_t mem;
316 	boolean_t ret = B_TRUE;
317 
318 	if (smbios_lookup_type(hdl, SMB_TYPE_MEMDEVICE, &sp) == -1) {
319 		warnx("failed to lookup SMBIOS memory device: %s",
320 		    smbios_errmsg(smbios_errno(hdl)));
321 		return (B_FALSE);
322 	}
323 
324 	if (smbios_info_memdevice(hdl, sp.smbstr_id, &mem) != 0) {
325 		warnx("failed to get SMBIOS memory device info: %s",
326 		    smbios_errmsg(smbios_errno(hdl)));
327 		return (B_FALSE);
328 	}
329 
330 	if (!smbios_test_memdevice_verify_common(&mem)) {
331 		return (B_FALSE);
332 	}
333 
334 	if (mem.smbmd_speed != 0xffff) {
335 		warnx("found wrong device speed: %u", mem.smbmd_speed);
336 		ret = B_FALSE;
337 	}
338 
339 	if (mem.smbmd_clkspeed != 0xffff) {
340 		warnx("found wrong device clkspeed: %u", mem.smbmd_clkspeed);
341 		ret = B_FALSE;
342 	}
343 
344 	if (mem.smbmd_extspeed != smbios_memdevice_extspeed) {
345 		warnx("found wrong device speed: %u", mem.smbmd_extspeed);
346 		ret = B_FALSE;
347 	}
348 
349 	if (mem.smbmd_extclkspeed != smbios_memdevice_extclkspeed) {
350 		warnx("found wrong device clkspeed: %u", mem.smbmd_extclkspeed);
351 		ret = B_FALSE;
352 	}
353 
354 	return (ret);
355 }
356