1 // SPDX-License-Identifier: GPL-2.0+
2 /*
3  * Tests for ACPI code generation via a device-property table
4  *
5  * Copyright 2019 Google LLC
6  * Written by Simon Glass <sjg@chromium.org>
7  */
8 
9 #include <common.h>
10 #include <dm.h>
11 #include <uuid.h>
12 #include <acpi/acpigen.h>
13 #include <acpi/acpi_dp.h>
14 #include <asm/unaligned.h>
15 #include <dm/acpi.h>
16 #include <dm/test.h>
17 #include <test/ut.h>
18 #include "acpi.h"
19 
20 /* Maximum size of the ACPI context needed for most tests */
21 #define ACPI_CONTEXT_SIZE	500
22 
23 #define TEST_INT8	0x7d
24 #define TEST_INT16	0x2345
25 #define TEST_INT32	0x12345678
26 #define TEST_INT64	0x4567890123456
27 #define TEST_STR	"testing acpi strings"
28 #define TEST_REF	"\\SB.I2C0.TPM2"
29 #define EXPECT_REF	"SB__I2C0TPM2"
30 
alloc_context(struct acpi_ctx ** ctxp)31 static int alloc_context(struct acpi_ctx **ctxp)
32 {
33 	return acpi_test_alloc_context_size(ctxp, ACPI_CONTEXT_SIZE);
34 
35 	return 0;
36 }
37 
free_context(struct acpi_ctx ** ctxp)38 static void free_context(struct acpi_ctx **ctxp)
39 {
40 	free(*ctxp);
41 	*ctxp = NULL;
42 }
43 
44 /* Test emitting an empty table */
dm_test_acpi_dp_new_table(struct unit_test_state * uts)45 static int dm_test_acpi_dp_new_table(struct unit_test_state *uts)
46 {
47 	struct acpi_ctx *ctx;
48 	struct acpi_dp *dp;
49 	u8 *ptr;
50 
51 	ut_assertok(alloc_context(&ctx));
52 
53 	dp = acpi_dp_new_table("FRED");
54 	ut_assertnonnull(dp);
55 
56 	ptr = acpigen_get_current(ctx);
57 	ut_assertok(acpi_dp_write(ctx, dp));
58 	ut_asserteq(10, acpigen_get_current(ctx) - ptr);
59 	ut_asserteq(NAME_OP, *(u8 *)ptr);
60 	ut_asserteq_strn("FRED", (char *)ptr + 1);
61 	ut_asserteq(PACKAGE_OP, ptr[5]);
62 	ut_asserteq(4, acpi_test_get_length(ptr + 6));
63 	ut_asserteq(0, ptr[9]);
64 
65 	free_context(&ctx);
66 
67 	return 0;
68 }
69 DM_TEST(dm_test_acpi_dp_new_table, 0);
70 
71 /* Test emitting an integer */
dm_test_acpi_dp_int(struct unit_test_state * uts)72 static int dm_test_acpi_dp_int(struct unit_test_state *uts)
73 {
74 	struct acpi_ctx *ctx;
75 	char uuid[UUID_STR_LEN + 1];
76 	struct acpi_dp *dp;
77 	u8 *ptr;
78 
79 	ut_assertok(alloc_context(&ctx));
80 
81 	dp = acpi_dp_new_table("FRED");
82 	ut_assertnonnull(dp);
83 	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT32));
84 
85 	ptr = acpigen_get_current(ctx);
86 	ut_assertok(acpi_dp_write(ctx, dp));
87 	ut_asserteq(54, acpigen_get_current(ctx) - ptr);
88 	ut_asserteq(NAME_OP, *(u8 *)ptr);
89 	ut_asserteq_strn("FRED", (char *)ptr + 1);
90 	ut_asserteq(PACKAGE_OP, ptr[5]);
91 	ut_asserteq(48, acpi_test_get_length(ptr + 6));
92 	ut_asserteq(2, ptr[9]);
93 
94 	/* UUID */
95 	ut_asserteq(BUFFER_OP, ptr[10]);
96 	ut_asserteq(22, acpi_test_get_length(ptr + 11));
97 	ut_asserteq(WORD_PREFIX, ptr[14]);
98 	ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
99 	uuid_bin_to_str(ptr + 17, uuid, 1);
100 	ut_asserteq_str(ACPI_DP_UUID, uuid);
101 
102 	/* Container package */
103 	ut_asserteq(PACKAGE_OP, ptr[33]);
104 	ut_asserteq(20, acpi_test_get_length(ptr + 34));
105 	ut_asserteq(1, ptr[37]);
106 
107 	/* Package with name and (integer) value */
108 	ut_asserteq(PACKAGE_OP, ptr[38]);
109 	ut_asserteq(15, acpi_test_get_length(ptr + 39));
110 	ut_asserteq(2, ptr[42]);
111 	ut_asserteq(STRING_PREFIX, ptr[43]);
112 	ut_asserteq_str("MARY", (char *)ptr + 44);
113 
114 	ut_asserteq(DWORD_PREFIX, ptr[49]);
115 	ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 50)));
116 
117 	free_context(&ctx);
118 
119 	return 0;
120 }
121 DM_TEST(dm_test_acpi_dp_int, 0);
122 
123 /* Test emitting a 64-bit integer */
dm_test_acpi_dp_int64(struct unit_test_state * uts)124 static int dm_test_acpi_dp_int64(struct unit_test_state *uts)
125 {
126 	struct acpi_ctx *ctx;
127 	struct acpi_dp *dp;
128 	u8 *ptr;
129 
130 	ut_assertok(alloc_context(&ctx));
131 
132 	dp = acpi_dp_new_table("FRED");
133 	ut_assertnonnull(dp);
134 	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT64));
135 
136 	ptr = acpigen_get_current(ctx);
137 	ut_assertok(acpi_dp_write(ctx, dp));
138 	ut_asserteq(58, acpigen_get_current(ctx) - ptr);
139 
140 	ut_asserteq(QWORD_PREFIX, ptr[49]);
141 	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 50)));
142 
143 	free_context(&ctx);
144 
145 	return 0;
146 }
147 DM_TEST(dm_test_acpi_dp_int64, 0);
148 
149 /* Test emitting a 16-bit integer */
dm_test_acpi_dp_int16(struct unit_test_state * uts)150 static int dm_test_acpi_dp_int16(struct unit_test_state *uts)
151 {
152 	struct acpi_ctx *ctx;
153 	struct acpi_dp *dp;
154 	u8 *ptr;
155 
156 	ut_assertok(alloc_context(&ctx));
157 
158 	dp = acpi_dp_new_table("FRED");
159 	ut_assertnonnull(dp);
160 	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT16));
161 
162 	ptr = acpigen_get_current(ctx);
163 	ut_assertok(acpi_dp_write(ctx, dp));
164 	ut_asserteq(52, acpigen_get_current(ctx) - ptr);
165 
166 	ut_asserteq(WORD_PREFIX, ptr[49]);
167 	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 50)));
168 
169 	free_context(&ctx);
170 
171 	return 0;
172 }
173 DM_TEST(dm_test_acpi_dp_int16, 0);
174 
175 /* Test emitting a 8-bit integer */
dm_test_acpi_dp_int8(struct unit_test_state * uts)176 static int dm_test_acpi_dp_int8(struct unit_test_state *uts)
177 {
178 	struct acpi_ctx *ctx;
179 	struct acpi_dp *dp;
180 	u8 *ptr;
181 
182 	ut_assertok(alloc_context(&ctx));
183 
184 	dp = acpi_dp_new_table("FRED");
185 	ut_assertnonnull(dp);
186 	ut_assertnonnull(acpi_dp_add_integer(dp, "MARY", TEST_INT8));
187 
188 	ptr = acpigen_get_current(ctx);
189 	ut_assertok(acpi_dp_write(ctx, dp));
190 	ut_asserteq(51, acpigen_get_current(ctx) - ptr);
191 
192 	ut_asserteq(BYTE_PREFIX, ptr[49]);
193 	ut_asserteq(TEST_INT8, ptr[50]);
194 
195 	free_context(&ctx);
196 
197 	return 0;
198 }
199 DM_TEST(dm_test_acpi_dp_int8, 0);
200 
201 /* Test emitting multiple values */
dm_test_acpi_dp_multiple(struct unit_test_state * uts)202 static int dm_test_acpi_dp_multiple(struct unit_test_state *uts)
203 {
204 	struct acpi_ctx *ctx;
205 	struct acpi_dp *dp;
206 	u8 *ptr;
207 
208 	ut_assertok(alloc_context(&ctx));
209 
210 	dp = acpi_dp_new_table("FRED");
211 	ut_assertnonnull(dp);
212 	ut_assertnonnull(acpi_dp_add_integer(dp, "int16", TEST_INT16));
213 	ut_assertnonnull(acpi_dp_add_string(dp, "str", TEST_STR));
214 	ut_assertnonnull(acpi_dp_add_reference(dp, "ref", TEST_REF));
215 
216 	ptr = acpigen_get_current(ctx);
217 	ut_assertok(acpi_dp_write(ctx, dp));
218 	ut_asserteq(110, acpigen_get_current(ctx) - ptr);
219 
220 	ut_asserteq(WORD_PREFIX, ptr[0x32]);
221 	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x33)));
222 	ut_asserteq(STRING_PREFIX, ptr[0x3f]);
223 	ut_asserteq_str(TEST_STR, (char *)ptr + 0x40);
224 	ut_asserteq(ROOT_PREFIX, ptr[0x5f]);
225 	ut_asserteq(MULTI_NAME_PREFIX, ptr[0x60]);
226 	ut_asserteq(3, ptr[0x61]);
227 	ut_asserteq_strn(EXPECT_REF, (char *)ptr + 0x62);
228 
229 	free_context(&ctx);
230 
231 	return 0;
232 }
233 DM_TEST(dm_test_acpi_dp_multiple, 0);
234 
235 /* Test emitting an array */
dm_test_acpi_dp_array(struct unit_test_state * uts)236 static int dm_test_acpi_dp_array(struct unit_test_state *uts)
237 {
238 	struct acpi_ctx *ctx;
239 	struct acpi_dp *dp;
240 	u64 speed[4];
241 	u8 *ptr;
242 
243 	ut_assertok(alloc_context(&ctx));
244 
245 	dp = acpi_dp_new_table("FRED");
246 	ut_assertnonnull(dp);
247 	speed[0] = TEST_INT8;
248 	speed[1] = TEST_INT16;
249 	speed[2] = TEST_INT32;
250 	speed[3] = TEST_INT64;
251 	ut_assertnonnull(acpi_dp_add_integer_array(dp, "speeds", speed,
252 						   ARRAY_SIZE(speed)));
253 
254 	ptr = acpigen_get_current(ctx);
255 	ut_assertok(acpi_dp_write(ctx, dp));
256 	ut_asserteq(75, acpigen_get_current(ctx) - ptr);
257 
258 	ut_asserteq(BYTE_PREFIX, ptr[0x38]);
259 	ut_asserteq(TEST_INT8, ptr[0x39]);
260 
261 	ut_asserteq(WORD_PREFIX, ptr[0x3a]);
262 	ut_asserteq(TEST_INT16, get_unaligned((u16 *)(ptr + 0x3b)));
263 
264 	ut_asserteq(DWORD_PREFIX, ptr[0x3d]);
265 	ut_asserteq(TEST_INT32, get_unaligned((u32 *)(ptr + 0x3e)));
266 
267 	ut_asserteq(QWORD_PREFIX, ptr[0x42]);
268 	ut_asserteq_64(TEST_INT64, get_unaligned((u64 *)(ptr + 0x43)));
269 
270 	free_context(&ctx);
271 
272 	return 0;
273 }
274 DM_TEST(dm_test_acpi_dp_array, 0);
275 
276 /* Test emitting a child */
dm_test_acpi_dp_child(struct unit_test_state * uts)277 static int dm_test_acpi_dp_child(struct unit_test_state *uts)
278 {
279 	struct acpi_ctx *ctx;
280 	struct acpi_dp *dp, *child1, *child2;
281 	char uuid[UUID_STR_LEN + 1];
282 	u8 *ptr, *pptr;
283 	int i;
284 
285 	ut_assertok(alloc_context(&ctx));
286 
287 	child1 = acpi_dp_new_table("child");
288 	ut_assertnonnull(child1);
289 	ut_assertnonnull(acpi_dp_add_integer(child1, "height", TEST_INT16));
290 
291 	child2 = acpi_dp_new_table("child");
292 	ut_assertnonnull(child2);
293 	ut_assertnonnull(acpi_dp_add_integer(child2, "age", TEST_INT8));
294 
295 	dp = acpi_dp_new_table("FRED");
296 	ut_assertnonnull(dp);
297 
298 	ut_assertnonnull(acpi_dp_add_child(dp, "anna", child1));
299 	ut_assertnonnull(acpi_dp_add_child(dp, "john", child2));
300 
301 	ptr = acpigen_get_current(ctx);
302 	ut_assertok(acpi_dp_write(ctx, dp));
303 	ut_asserteq(178, acpigen_get_current(ctx) - ptr);
304 
305 	/* UUID for child extension using Hierarchical Data Extension UUID */
306 	ut_asserteq(BUFFER_OP, ptr[10]);
307 	ut_asserteq(22, acpi_test_get_length(ptr + 11));
308 	ut_asserteq(WORD_PREFIX, ptr[14]);
309 	ut_asserteq(16, get_unaligned((u16 *)(ptr + 15)));
310 	uuid_bin_to_str(ptr + 17, uuid, 1);
311 	ut_asserteq_str(ACPI_DP_CHILD_UUID, uuid);
312 
313 	/* Package with two children */
314 	ut_asserteq(PACKAGE_OP, ptr[0x21]);
315 	ut_asserteq(0x28, acpi_test_get_length(ptr + 0x22));
316 	ut_asserteq(2, ptr[0x25]);
317 
318 	/* First we expect the two children as string/value */
319 	pptr = ptr + 0x26;
320 	for (i = 0; i < 2; i++) {
321 		ut_asserteq(PACKAGE_OP, pptr[0]);
322 		ut_asserteq(0x11, acpi_test_get_length(pptr + 1));
323 		ut_asserteq(2, pptr[4]);
324 		ut_asserteq(STRING_PREFIX, pptr[5]);
325 		ut_asserteq_str(i ? "john" : "anna", (char *)pptr + 6);
326 		ut_asserteq(STRING_PREFIX, pptr[11]);
327 		ut_asserteq_str("child", (char *)pptr + 12);
328 		pptr += 0x12;
329 	}
330 
331 	/* Write the two children */
332 	ut_asserteq(0x4a, pptr - ptr);
333 	for (i = 0; i < 2; i++) {
334 		const char *prop = i ? "age" : "height";
335 		const int datalen = i ? 1 : 2;
336 		int len = strlen(prop) + 1;
337 
338 		ut_asserteq(NAME_OP, pptr[0]);
339 		ut_asserteq_strn("chil", (char *)pptr + 1);
340 		ut_asserteq(PACKAGE_OP, pptr[5]);
341 		ut_asserteq(0x27 + len + datalen, acpi_test_get_length(pptr + 6));
342 		ut_asserteq(2, pptr[9]);
343 
344 		/* UUID */
345 		ut_asserteq(BUFFER_OP, pptr[10]);
346 		ut_asserteq(22, acpi_test_get_length(pptr + 11));
347 		ut_asserteq(WORD_PREFIX, pptr[14]);
348 		ut_asserteq(16, get_unaligned((u16 *)(pptr + 15)));
349 		uuid_bin_to_str(pptr + 17, uuid, 1);
350 		ut_asserteq_str(ACPI_DP_UUID, uuid);
351 		pptr += 33;
352 
353 		/* Containing package */
354 		ut_asserteq(i ? 0xa1 : 0x6b, pptr - ptr);
355 		ut_asserteq(PACKAGE_OP, pptr[0]);
356 		ut_asserteq(0xb + len + datalen, acpi_test_get_length(pptr + 1));
357 		ut_asserteq(1, pptr[4]);
358 
359 		/* Package containing the property-name string and the value */
360 		pptr += 5;
361 		ut_asserteq(i ? 0xa6 : 0x70, pptr - ptr);
362 		ut_asserteq(PACKAGE_OP, pptr[0]);
363 		ut_asserteq(6 + len + datalen, acpi_test_get_length(pptr + 1));
364 		ut_asserteq(2, pptr[4]);
365 
366 		ut_asserteq(STRING_PREFIX, pptr[5]);
367 		ut_asserteq_str(i ? "age" : "height", (char *)pptr + 6);
368 		pptr += 6 + len;
369 		if (i) {
370 			ut_asserteq(BYTE_PREFIX, pptr[0]);
371 			ut_asserteq(TEST_INT8, pptr[1]);
372 		} else {
373 			ut_asserteq(WORD_PREFIX, pptr[0]);
374 			ut_asserteq(TEST_INT16,
375 				    get_unaligned((u16 *)(pptr + 1)));
376 		}
377 		pptr += 1 + datalen;
378 	}
379 	ut_asserteq(178, pptr - ptr);
380 
381 	free_context(&ctx);
382 
383 	return 0;
384 }
385 DM_TEST(dm_test_acpi_dp_child, 0);
386 
387 /* Test emitting a GPIO */
dm_test_acpi_dp_gpio(struct unit_test_state * uts)388 static int dm_test_acpi_dp_gpio(struct unit_test_state *uts)
389 {
390 	struct acpi_ctx *ctx;
391 	struct acpi_dp *dp;
392 	u8 *ptr, *pptr;
393 
394 	ut_assertok(alloc_context(&ctx));
395 
396 	dp = acpi_dp_new_table("FRED");
397 	ut_assertnonnull(dp);
398 
399 	/* Try a few different parameters */
400 	ut_assertnonnull(acpi_dp_add_gpio(dp, "reset", TEST_REF, 0x23, 0x24,
401 					  ACPI_GPIO_ACTIVE_HIGH));
402 	ut_assertnonnull(acpi_dp_add_gpio(dp, "allow", TEST_REF, 0, 0,
403 					  ACPI_GPIO_ACTIVE_LOW));
404 
405 	ptr = acpigen_get_current(ctx);
406 	ut_assertok(acpi_dp_write(ctx, dp));
407 	ut_asserteq(0x6e, acpigen_get_current(ctx) - ptr);
408 
409 	pptr = ptr + 0x2c; //0x3a;
410 	ut_asserteq_str("reset", (char *)pptr);
411 	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
412 	ut_asserteq(0x23, pptr[0x1b]);
413 	ut_asserteq(0x24, pptr[0x1d]);
414 	ut_asserteq(ZERO_OP, pptr[0x1e]);
415 
416 	pptr = ptr + 0x51;
417 	ut_asserteq_str("allow", (char *)pptr);
418 	ut_asserteq_strn(EXPECT_REF, (char *)pptr + 0xe);
419 	ut_asserteq(ZERO_OP, pptr[0x1a]);
420 	ut_asserteq(ZERO_OP, pptr[0x1b]);
421 	ut_asserteq(ONE_OP, pptr[0x1c]);
422 
423 	return 0;
424 }
425 DM_TEST(dm_test_acpi_dp_gpio, 0);
426 
427 /* Test copying info from the device tree to ACPI tables */
dm_test_acpi_dp_copy(struct unit_test_state * uts)428 static int dm_test_acpi_dp_copy(struct unit_test_state *uts)
429 {
430 	struct acpi_ctx *ctx;
431 	struct udevice *dev;
432 	struct acpi_dp *dp;
433 	ofnode node;
434 	u8 *ptr;
435 
436 	ut_assertok(alloc_context(&ctx));
437 
438 	dp = acpi_dp_new_table("FRED");
439 	ut_assertnonnull(dp);
440 
441 	ut_assertok(uclass_get_device(UCLASS_TEST_FDT, 0, &dev));
442 	ut_asserteq_str("a-test", dev->name);
443 
444 	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "int-value"));
445 	ut_asserteq(-EINVAL, acpi_dp_dev_copy_int(dev, dp, "missing-value"));
446 	ut_assertok(acpi_dp_dev_copy_int(dev, dp, "uint-value"));
447 
448 	ut_assertok(acpi_dp_dev_copy_str(dev, dp, "str-value"));
449 	ut_asserteq(-EINVAL, acpi_dp_dev_copy_str(dev, dp, "missing-value"));
450 
451 	node = ofnode_path("/chosen");
452 	ut_assert(ofnode_valid(node));
453 	ut_assertok(acpi_dp_ofnode_copy_int(node, dp, "int-values"));
454 	ut_asserteq(-EINVAL,
455 		    acpi_dp_ofnode_copy_int(node, dp, "missing-value"));
456 
457 	ut_assertok(acpi_dp_ofnode_copy_str(node, dp, "setting"));
458 	ut_asserteq(-EINVAL,
459 		    acpi_dp_ofnode_copy_str(node, dp, "missing-value"));
460 
461 	ptr = acpigen_get_current(ctx);
462 	ut_assertok(acpi_dp_write(ctx, dp));
463 	ut_asserteq(0x9d, acpigen_get_current(ctx) - ptr);
464 
465 	ut_asserteq(STRING_PREFIX, ptr[0x2b]);
466 	ut_asserteq_str("int-value", (char *)ptr + 0x2c);
467 	ut_asserteq(WORD_PREFIX, ptr[0x36]);
468 	ut_asserteq(1234, get_unaligned((u16 *)(ptr + 0x37)));
469 
470 	ut_asserteq(STRING_PREFIX, ptr[0x3e]);
471 	ut_asserteq_str("uint-value", (char *)ptr + 0x3f);
472 	ut_asserteq(DWORD_PREFIX, ptr[0x4a]);
473 	ut_asserteq(-1234, get_unaligned((u32 *)(ptr + 0x4b)));
474 
475 	ut_asserteq(STRING_PREFIX, ptr[0x54]);
476 	ut_asserteq_str("str-value", (char *)ptr + 0x55);
477 	ut_asserteq(STRING_PREFIX, ptr[0x5f]);
478 	ut_asserteq_str("test string", (char *)ptr + 0x60);
479 
480 	ut_asserteq(STRING_PREFIX, ptr[0x71]);
481 	ut_asserteq_str("int-values", (char *)ptr + 0x72);
482 	ut_asserteq(WORD_PREFIX, ptr[0x7d]);
483 	ut_asserteq(0x1937, get_unaligned((u16 *)(ptr + 0x7e)));
484 
485 	ut_asserteq(STRING_PREFIX, ptr[0x85]);
486 	ut_asserteq_str("setting", (char *)ptr + 0x86);
487 	ut_asserteq(STRING_PREFIX, ptr[0x8e]);
488 	ut_asserteq_str("sunrise ohoka", (char *)(ptr + 0x8f));
489 
490 	return 0;
491 }
492 DM_TEST(dm_test_acpi_dp_copy, UT_TESTF_SCAN_PDATA | UT_TESTF_SCAN_FDT);
493