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