1 /*
2  * Copyright (c) 2023 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <string.h>
9 #include <inttypes.h>
10 
11 #include "mock.h"
12 
13 #include <zephyr/acpi/acpi.h>
14 #include <lib/acpi/acpi.c>
15 #include "assert.h"
16 
17 #include <zephyr/fff.h>
18 DEFINE_FFF_GLOBALS;
19 
20 struct DMAR {
21 	ACPI_TABLE_DMAR header;
22 
23 	/* Hardware Unit 0 */
24 	struct {
25 		ACPI_DMAR_HARDWARE_UNIT header;
26 
27 		struct {
28 			ACPI_DMAR_DEVICE_SCOPE header;
29 			ACPI_DMAR_PCI_PATH path0;
30 		} ds0;
31 
32 		struct {
33 			ACPI_DMAR_DEVICE_SCOPE header;
34 			ACPI_DMAR_PCI_PATH path0;
35 		} ds1;
36 	} unit0;
37 
38 	/* Hardware Unit 1 */
39 	struct {
40 		ACPI_DMAR_HARDWARE_UNIT header;
41 
42 		struct {
43 			ACPI_DMAR_DEVICE_SCOPE header;
44 			ACPI_DMAR_PCI_PATH path0;
45 		} ds0;
46 
47 		struct {
48 			ACPI_DMAR_DEVICE_SCOPE header;
49 			ACPI_DMAR_PCI_PATH path0;
50 		} ds1;
51 	} unit1;
52 };
53 
54 static struct DMAR dmar0;
55 
dmar_initialize(struct DMAR * dmar)56 static void dmar_initialize(struct DMAR *dmar)
57 {
58 	dmar->header.Header.Length = sizeof(struct DMAR);
59 
60 	dmar->unit0.header.Header.Length = sizeof(dmar->unit0);
61 	dmar->unit0.ds0.header.Length = sizeof(dmar->unit0.ds0);
62 	dmar->unit0.ds1.header.Length = sizeof(dmar->unit0.ds1);
63 
64 	dmar->unit1.header.Header.Length = sizeof(dmar->unit1);
65 	dmar->unit1.ds0.header.Length = sizeof(dmar->unit1.ds0);
66 	dmar->unit1.ds1.header.Length = sizeof(dmar->unit1.ds1);
67 }
68 
ZTEST(lib_acpi,test_nop)69 ZTEST(lib_acpi, test_nop)
70 {
71 }
72 
count_subtables(ACPI_DMAR_HEADER * subtable,void * arg)73 static void count_subtables(ACPI_DMAR_HEADER *subtable, void *arg)
74 {
75 	uint8_t *count = arg;
76 
77 	(*count)++;
78 }
79 
80 FAKE_VOID_FUNC(subtable_nop, ACPI_DMAR_HEADER *, void *);
81 
ZTEST(lib_acpi,test_dmar_foreach_subtable)82 ZTEST(lib_acpi, test_dmar_foreach_subtable)
83 {
84 	uint8_t count = 0;
85 
86 	dmar_initialize(&dmar0);
87 
88 	acpi_dmar_foreach_subtable((void *)&dmar0, count_subtables, &count);
89 	zassert_equal(count, 2);
90 
91 	TC_PRINT("Counted %u hardware units\n", count);
92 }
93 
ZTEST(lib_acpi,test_dmar_foreach_subtable_invalid_unit_size_zero)94 ZTEST(lib_acpi, test_dmar_foreach_subtable_invalid_unit_size_zero)
95 {
96 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header;
97 
98 	dmar_initialize(&dmar0);
99 
100 	/* Set invalid hardware unit size */
101 	hu->Header.Length = 0;
102 
103 	expect_assert();
104 
105 	/* Expect assert, use fake void function as a callback */
106 	acpi_dmar_foreach_subtable((void *)&dmar0, subtable_nop, NULL);
107 
108 	zassert_unreachable("Missed assert catch");
109 }
110 
ZTEST(lib_acpi,test_dmar_foreach_subtable_invalid_unit_size_big)111 ZTEST(lib_acpi, test_dmar_foreach_subtable_invalid_unit_size_big)
112 {
113 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header;
114 
115 	dmar_initialize(&dmar0);
116 
117 	/* Set invalid hardware unit size */
118 	hu->Header.Length = sizeof(dmar0.unit1) + 1;
119 
120 	expect_assert();
121 
122 	/* Expect assert, use fake void function as a callback */
123 	acpi_dmar_foreach_subtable((void *)&dmar0, subtable_nop, NULL);
124 
125 	zassert_unreachable("Missed assert catch");
126 }
127 
count_devscopes(ACPI_DMAR_DEVICE_SCOPE * devscope,void * arg)128 static void count_devscopes(ACPI_DMAR_DEVICE_SCOPE *devscope, void *arg)
129 {
130 	uint8_t *count = arg;
131 
132 	(*count)++;
133 }
134 
135 FAKE_VOID_FUNC(devscope_nop, ACPI_DMAR_DEVICE_SCOPE *, void *);
136 
ZTEST(lib_acpi,test_dmar_foreach_devscope)137 ZTEST(lib_acpi, test_dmar_foreach_devscope)
138 {
139 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header;
140 	uint8_t count = 0;
141 
142 	dmar_initialize(&dmar0);
143 
144 	acpi_dmar_foreach_devscope(hu, count_devscopes, &count);
145 	zassert_equal(count, 2);
146 
147 	TC_PRINT("Counted %u device scopes\n", count);
148 }
149 
ZTEST(lib_acpi,test_dmar_foreach_devscope_invalid_unit_size)150 ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_unit_size)
151 {
152 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header;
153 
154 	dmar_initialize(&dmar0);
155 
156 	/* Set invalid hardware unit size */
157 	hu->Header.Length = 0;
158 
159 	expect_assert();
160 
161 	/* Expect assert, use fake void function as a callback */
162 	acpi_dmar_foreach_devscope(hu, devscope_nop, NULL);
163 
164 	zassert_unreachable("Missed assert catch");
165 }
166 
ZTEST(lib_acpi,test_dmar_foreach_devscope_invalid_devscope_size_zero)167 ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_devscope_size_zero)
168 {
169 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit0.header;
170 	ACPI_DMAR_DEVICE_SCOPE *devscope = &dmar0.unit0.ds0.header;
171 
172 	dmar_initialize(&dmar0);
173 
174 	/* Set invalid device scope size */
175 	devscope->Length = 0;
176 
177 	expect_assert();
178 
179 	/* Expect assert, use fake void function as a callback */
180 	acpi_dmar_foreach_devscope(hu, devscope_nop, NULL);
181 
182 	zassert_unreachable("Missed assert catch");
183 }
184 
ZTEST(lib_acpi,test_dmar_foreach_devscope_invalid_devscope_size_big)185 ZTEST(lib_acpi, test_dmar_foreach_devscope_invalid_devscope_size_big)
186 {
187 	ACPI_DMAR_HARDWARE_UNIT *hu = &dmar0.unit1.header;
188 	ACPI_DMAR_DEVICE_SCOPE *devscope = &dmar0.unit1.ds1.header;
189 
190 	dmar_initialize(&dmar0);
191 
192 	/* Set invalid device scope size */
193 	devscope->Length = sizeof(dmar0.unit1.ds1) + 1;
194 
195 	expect_assert();
196 
197 	/* Expect assert, use fake void function as a callback */
198 	acpi_dmar_foreach_devscope(hu, devscope_nop, NULL);
199 
200 	zassert_unreachable("Missed assert catch");
201 }
202 
203 /**
204  * Redefine AcpiGetTable to provide our static table
205  */
206 DECLARE_FAKE_VALUE_FUNC(ACPI_STATUS, AcpiGetTable, char *, UINT32,
207 			struct acpi_table_header **);
dmar_custom_get_table(char * Signature,UINT32 Instance,ACPI_TABLE_HEADER ** OutTable)208 static ACPI_STATUS dmar_custom_get_table(char *Signature, UINT32 Instance,
209 				  ACPI_TABLE_HEADER **OutTable)
210 {
211 	*OutTable = (ACPI_TABLE_HEADER *)&dmar0;
212 
213 	return AE_OK;
214 }
215 
ZTEST(lib_acpi,test_dmar_ioapic_get)216 ZTEST(lib_acpi, test_dmar_ioapic_get)
217 {
218 	union acpi_dmar_id fake_path = {
219 		.bits.bus = 0xab,
220 		.bits.device = 0xc,
221 		.bits.function = 0b101,
222 	};
223 	uint16_t ioapic;
224 	int ret;
225 
226 	dmar_initialize(&dmar0);
227 
228 	/* Set IOAPIC device scope */
229 	dmar0.unit1.ds1.header.EntryType = ACPI_DMAR_SCOPE_TYPE_IOAPIC;
230 
231 	/* Set some arbitrary Bus and PCI path */
232 	dmar0.unit1.ds1.header.Bus = fake_path.bits.bus;
233 	dmar0.unit1.ds1.path0.Device = fake_path.bits.device;
234 	dmar0.unit1.ds1.path0.Function = fake_path.bits.function;
235 
236 	/* Return our dmar0 table */
237 	AcpiGetTable_fake.custom_fake = dmar_custom_get_table;
238 
239 	zassert_equal(AcpiGetTable_fake.call_count, 0);
240 
241 	ret = acpi_dmar_ioapic_get(&ioapic);
242 	zassert_ok(ret, "Failed getting ioapic");
243 
244 	/* Verify AcpiGetTable called */
245 	zassert_equal(AcpiGetTable_fake.call_count, 1);
246 
247 	zassert_equal(ioapic, fake_path.raw, "Got wrong ioapic");
248 
249 	TC_PRINT("Found ioapic id 0x%x\n", ioapic);
250 }
251 
test_before(void * data)252 static void test_before(void *data)
253 {
254 	ASSERT_FFF_FAKES_LIST(RESET_FAKE);
255 }
256 
257 ZTEST_SUITE(lib_acpi, NULL, NULL, test_before, NULL, NULL);
258