]>
Commit | Line | Data |
---|---|---|
d4d2fdf2 KK |
1 | /** @file\r |
2 | PPTT table parser\r | |
3 | \r | |
b8504826 | 4 | Copyright (c) 2019 - 2020, ARM Limited. All rights reserved.\r |
56ba3746 | 5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r |
d4d2fdf2 KK |
6 | \r |
7 | @par Reference(s):\r | |
5a27f7a2 KK |
8 | - ACPI 6.3 Specification - January 2019\r |
9 | - ARM Architecture Reference Manual ARMv8 (D.a)\r | |
d4d2fdf2 KK |
10 | **/\r |
11 | \r | |
12 | #include <Library/PrintLib.h>\r | |
13 | #include <Library/UefiLib.h>\r | |
14 | #include "AcpiParser.h"\r | |
5a27f7a2 KK |
15 | #include "AcpiView.h"\r |
16 | #include "PpttParser.h"\r | |
d4d2fdf2 KK |
17 | \r |
18 | // Local variables\r | |
19 | STATIC CONST UINT8* ProcessorTopologyStructureType;\r | |
20 | STATIC CONST UINT8* ProcessorTopologyStructureLength;\r | |
21 | STATIC CONST UINT32* NumberOfPrivateResources;\r | |
22 | STATIC ACPI_DESCRIPTION_HEADER_INFO AcpiHdrInfo;\r | |
23 | \r | |
24 | /**\r | |
5a27f7a2 KK |
25 | This function validates the Cache Type Structure (Type 1) 'Number of sets'\r |
26 | field.\r | |
27 | \r | |
28 | @param [in] Ptr Pointer to the start of the field data.\r | |
29 | @param [in] Context Pointer to context specific information e.g. this\r | |
30 | could be a pointer to the ACPI table header.\r | |
d4d2fdf2 | 31 | **/\r |
5a27f7a2 KK |
32 | STATIC\r |
33 | VOID\r | |
34 | EFIAPI\r | |
35 | ValidateCacheNumberOfSets (\r | |
36 | IN UINT8* Ptr,\r | |
37 | IN VOID* Context\r | |
38 | )\r | |
39 | {\r | |
40 | UINT32 NumberOfSets;\r | |
41 | NumberOfSets = *(UINT32*)Ptr;\r | |
42 | \r | |
43 | if (NumberOfSets == 0) {\r | |
44 | IncrementErrorCount ();\r | |
45 | Print (L"\nERROR: Cache number of sets must be greater than 0");\r | |
46 | return;\r | |
47 | }\r | |
48 | \r | |
49 | #if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r | |
50 | if (NumberOfSets > PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX) {\r | |
51 | IncrementErrorCount ();\r | |
52 | Print (\r | |
53 | L"\nERROR: When ARMv8.3-CCIDX is implemented the maximum cache number of "\r | |
54 | L"sets must be less than or equal to %d",\r | |
55 | PPTT_ARM_CCIDX_CACHE_NUMBER_OF_SETS_MAX\r | |
56 | );\r | |
57 | return;\r | |
58 | }\r | |
59 | \r | |
60 | if (NumberOfSets > PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX) {\r | |
61 | IncrementWarningCount ();\r | |
62 | Print (\r | |
63 | L"\nWARNING: Without ARMv8.3-CCIDX, the maximum cache number of sets "\r | |
64 | L"must be less than or equal to %d. Ignore this message if "\r | |
65 | L"ARMv8.3-CCIDX is implemented",\r | |
66 | PPTT_ARM_CACHE_NUMBER_OF_SETS_MAX\r | |
67 | );\r | |
68 | return;\r | |
69 | }\r | |
70 | #endif\r | |
71 | \r | |
72 | }\r | |
73 | \r | |
74 | /**\r | |
75 | This function validates the Cache Type Structure (Type 1) 'Associativity'\r | |
76 | field.\r | |
77 | \r | |
78 | @param [in] Ptr Pointer to the start of the field data.\r | |
79 | @param [in] Context Pointer to context specific information e.g. this\r | |
80 | could be a pointer to the ACPI table header.\r | |
81 | **/\r | |
82 | STATIC\r | |
83 | VOID\r | |
84 | EFIAPI\r | |
85 | ValidateCacheAssociativity (\r | |
86 | IN UINT8* Ptr,\r | |
87 | IN VOID* Context\r | |
88 | )\r | |
89 | {\r | |
90 | UINT8 Associativity;\r | |
91 | Associativity = *(UINT8*)Ptr;\r | |
92 | \r | |
93 | if (Associativity == 0) {\r | |
94 | IncrementErrorCount ();\r | |
95 | Print (L"\nERROR: Cache associativity must be greater than 0");\r | |
96 | return;\r | |
97 | }\r | |
98 | }\r | |
d4d2fdf2 KK |
99 | \r |
100 | /**\r | |
101 | This function validates the Cache Type Structure (Type 1) Line size field.\r | |
102 | \r | |
103 | @param [in] Ptr Pointer to the start of the field data.\r | |
104 | @param [in] Context Pointer to context specific information e.g. this\r | |
105 | could be a pointer to the ACPI table header.\r | |
106 | **/\r | |
107 | STATIC\r | |
108 | VOID\r | |
109 | EFIAPI\r | |
110 | ValidateCacheLineSize (\r | |
111 | IN UINT8* Ptr,\r | |
112 | IN VOID* Context\r | |
113 | )\r | |
114 | {\r | |
115 | #if defined(MDE_CPU_ARM) || defined (MDE_CPU_AARCH64)\r | |
116 | // Reference: ARM Architecture Reference Manual ARMv8 (D.a)\r | |
117 | // Section D12.2.25: CCSIDR_EL1, Current Cache Size ID Register\r | |
118 | // LineSize, bits [2:0]\r | |
119 | // (Log2(Number of bytes in cache line)) - 4.\r | |
120 | \r | |
121 | UINT16 LineSize;\r | |
122 | LineSize = *(UINT16*)Ptr;\r | |
123 | \r | |
5a27f7a2 KK |
124 | if ((LineSize < PPTT_ARM_CACHE_LINE_SIZE_MIN) ||\r |
125 | (LineSize > PPTT_ARM_CACHE_LINE_SIZE_MAX)) {\r | |
d4d2fdf2 KK |
126 | IncrementErrorCount ();\r |
127 | Print (\r | |
5a27f7a2 KK |
128 | L"\nERROR: The cache line size must be between %d and %d bytes"\r |
129 | L" on ARM Platforms.",\r | |
130 | PPTT_ARM_CACHE_LINE_SIZE_MIN,\r | |
131 | PPTT_ARM_CACHE_LINE_SIZE_MAX\r | |
d4d2fdf2 KK |
132 | );\r |
133 | return;\r | |
134 | }\r | |
135 | \r | |
136 | if ((LineSize & (LineSize - 1)) != 0) {\r | |
137 | IncrementErrorCount ();\r | |
138 | Print (L"\nERROR: The cache line size is not a power of 2.");\r | |
139 | }\r | |
140 | #endif\r | |
141 | }\r | |
142 | \r | |
143 | /**\r | |
144 | This function validates the Cache Type Structure (Type 1) Attributes field.\r | |
145 | \r | |
146 | @param [in] Ptr Pointer to the start of the field data.\r | |
147 | @param [in] Context Pointer to context specific information e.g. this\r | |
148 | could be a pointer to the ACPI table header.\r | |
149 | **/\r | |
150 | STATIC\r | |
151 | VOID\r | |
152 | EFIAPI\r | |
153 | ValidateCacheAttributes (\r | |
154 | IN UINT8* Ptr,\r | |
155 | IN VOID* Context\r | |
156 | )\r | |
157 | {\r | |
d4d2fdf2 KK |
158 | // Reference: Advanced Configuration and Power Interface (ACPI) Specification\r |
159 | // Version 6.2 Errata A, September 2017\r | |
160 | // Table 5-153: Cache Type Structure\r | |
d4d2fdf2 KK |
161 | UINT8 Attributes;\r |
162 | Attributes = *(UINT8*)Ptr;\r | |
163 | \r | |
164 | if ((Attributes & 0xE0) != 0) {\r | |
165 | IncrementErrorCount ();\r | |
166 | Print (\r | |
167 | L"\nERROR: Attributes bits [7:5] are reserved and must be zero.",\r | |
168 | Attributes\r | |
169 | );\r | |
170 | return;\r | |
171 | }\r | |
d4d2fdf2 KK |
172 | }\r |
173 | \r | |
5a27f7a2 KK |
174 | /**\r |
175 | An ACPI_PARSER array describing the ACPI PPTT Table.\r | |
176 | **/\r | |
177 | STATIC CONST ACPI_PARSER PpttParser[] = {\r | |
178 | PARSE_ACPI_HEADER (&AcpiHdrInfo)\r | |
179 | };\r | |
180 | \r | |
d4d2fdf2 KK |
181 | /**\r |
182 | An ACPI_PARSER array describing the processor topology structure header.\r | |
183 | **/\r | |
184 | STATIC CONST ACPI_PARSER ProcessorTopologyStructureHeaderParser[] = {\r | |
185 | {L"Type", 1, 0, NULL, NULL, (VOID**)&ProcessorTopologyStructureType,\r | |
186 | NULL, NULL},\r | |
187 | {L"Length", 1, 1, NULL, NULL, (VOID**)&ProcessorTopologyStructureLength,\r | |
188 | NULL, NULL},\r | |
189 | {L"Reserved", 2, 2, NULL, NULL, NULL, NULL, NULL}\r | |
190 | };\r | |
191 | \r | |
192 | /**\r | |
193 | An ACPI_PARSER array describing the Processor Hierarchy Node Structure - Type 0.\r | |
194 | **/\r | |
195 | STATIC CONST ACPI_PARSER ProcessorHierarchyNodeStructureParser[] = {\r | |
196 | {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r | |
197 | {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r | |
198 | {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r | |
199 | \r | |
200 | {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r | |
201 | {L"Parent", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r | |
202 | {L"ACPI Processor ID", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r | |
203 | {L"Number of private resources", 4, 16, L"%d", NULL,\r | |
204 | (VOID**)&NumberOfPrivateResources, NULL, NULL}\r | |
205 | };\r | |
206 | \r | |
207 | /**\r | |
208 | An ACPI_PARSER array describing the Cache Type Structure - Type 1.\r | |
209 | **/\r | |
210 | STATIC CONST ACPI_PARSER CacheTypeStructureParser[] = {\r | |
211 | {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r | |
212 | {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r | |
213 | {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r | |
214 | \r | |
215 | {L"Flags", 4, 4, L"0x%x", NULL, NULL, NULL, NULL},\r | |
216 | {L"Next Level of Cache", 4, 8, L"0x%x", NULL, NULL, NULL, NULL},\r | |
217 | {L"Size", 4, 12, L"0x%x", NULL, NULL, NULL, NULL},\r | |
5a27f7a2 KK |
218 | {L"Number of sets", 4, 16, L"%d", NULL, NULL, ValidateCacheNumberOfSets, NULL},\r |
219 | {L"Associativity", 1, 20, L"%d", NULL, NULL, ValidateCacheAssociativity, NULL},\r | |
d4d2fdf2 KK |
220 | {L"Attributes", 1, 21, L"0x%x", NULL, NULL, ValidateCacheAttributes, NULL},\r |
221 | {L"Line size", 2, 22, L"%d", NULL, NULL, ValidateCacheLineSize, NULL}\r | |
222 | };\r | |
223 | \r | |
224 | /**\r | |
225 | An ACPI_PARSER array describing the ID Type Structure - Type 2.\r | |
226 | **/\r | |
227 | STATIC CONST ACPI_PARSER IdStructureParser[] = {\r | |
228 | {L"Type", 1, 0, L"0x%x", NULL, NULL, NULL, NULL},\r | |
229 | {L"Length", 1, 1, L"%d", NULL, NULL, NULL, NULL},\r | |
230 | {L"Reserved", 2, 2, L"0x%x", NULL, NULL, NULL, NULL},\r | |
231 | \r | |
7b84de93 | 232 | {L"VENDOR_ID", 4, 4, NULL, Dump4Chars, NULL, NULL, NULL},\r |
d4d2fdf2 KK |
233 | {L"LEVEL_1_ID", 8, 8, L"0x%x", NULL, NULL, NULL, NULL},\r |
234 | {L"LEVEL_2_ID", 8, 16, L"0x%x", NULL, NULL, NULL, NULL},\r | |
235 | {L"MAJOR_REV", 2, 24, L"0x%x", NULL, NULL, NULL, NULL},\r | |
236 | {L"MINOR_REV", 2, 26, L"0x%x", NULL, NULL, NULL, NULL},\r | |
237 | {L"SPIN_REV", 2, 28, L"0x%x", NULL, NULL, NULL, NULL},\r | |
238 | };\r | |
239 | \r | |
240 | /**\r | |
241 | This function parses the Processor Hierarchy Node Structure (Type 0).\r | |
242 | \r | |
243 | @param [in] Ptr Pointer to the start of the Processor Hierarchy Node\r | |
244 | Structure data.\r | |
245 | @param [in] Length Length of the Processor Hierarchy Node Structure.\r | |
246 | **/\r | |
247 | STATIC\r | |
248 | VOID\r | |
249 | DumpProcessorHierarchyNodeStructure (\r | |
250 | IN UINT8* Ptr,\r | |
251 | IN UINT8 Length\r | |
252 | )\r | |
253 | {\r | |
f34b38fa | 254 | UINT32 Offset;\r |
d4d2fdf2 KK |
255 | UINT32 Index;\r |
256 | CHAR16 Buffer[OUTPUT_FIELD_COLUMN_WIDTH];\r | |
257 | \r | |
258 | Offset = ParseAcpi (\r | |
259 | TRUE,\r | |
260 | 2,\r | |
261 | "Processor Hierarchy Node Structure",\r | |
262 | Ptr,\r | |
263 | Length,\r | |
264 | PARSER_PARAMS (ProcessorHierarchyNodeStructureParser)\r | |
265 | );\r | |
266 | \r | |
84a534b4 KK |
267 | // Check if the values used to control the parsing logic have been\r |
268 | // successfully read.\r | |
269 | if (NumberOfPrivateResources == NULL) {\r | |
270 | IncrementErrorCount ();\r | |
271 | Print (\r | |
272 | L"ERROR: Insufficient Processor Hierarchy Node length. Length = %d.\n",\r | |
273 | Length\r | |
274 | );\r | |
275 | return;\r | |
276 | }\r | |
277 | \r | |
5f066122 KK |
278 | // Make sure the Private Resource array lies inside this structure\r |
279 | if (Offset + (*NumberOfPrivateResources * sizeof (UINT32)) > Length) {\r | |
280 | IncrementErrorCount ();\r | |
281 | Print (\r | |
282 | L"ERROR: Invalid Number of Private Resources. " \\r | |
283 | L"PrivateResourceCount = %d. RemainingBufferLength = %d. " \\r | |
284 | L"Parsing of this structure aborted.\n",\r | |
285 | *NumberOfPrivateResources,\r | |
286 | Length - Offset\r | |
287 | );\r | |
288 | return;\r | |
289 | }\r | |
290 | \r | |
d4d2fdf2 | 291 | Index = 0;\r |
5f066122 KK |
292 | \r |
293 | // Parse the specified number of private resource references or the Processor\r | |
294 | // Hierarchy Node length. Whichever is minimum.\r | |
d4d2fdf2 KK |
295 | while (Index < *NumberOfPrivateResources) {\r |
296 | UnicodeSPrint (\r | |
297 | Buffer,\r | |
298 | sizeof (Buffer),\r | |
299 | L"Private resources [%d]",\r | |
300 | Index\r | |
301 | );\r | |
302 | \r | |
303 | PrintFieldName (4, Buffer);\r | |
304 | Print (\r | |
305 | L"0x%x\n",\r | |
5f066122 | 306 | *((UINT32*)(Ptr + Offset))\r |
d4d2fdf2 KK |
307 | );\r |
308 | \r | |
5f066122 | 309 | Offset += sizeof (UINT32);\r |
d4d2fdf2 KK |
310 | Index++;\r |
311 | }\r | |
312 | }\r | |
313 | \r | |
314 | /**\r | |
315 | This function parses the Cache Type Structure (Type 1).\r | |
316 | \r | |
317 | @param [in] Ptr Pointer to the start of the Cache Type Structure data.\r | |
318 | @param [in] Length Length of the Cache Type Structure.\r | |
319 | **/\r | |
320 | STATIC\r | |
321 | VOID\r | |
322 | DumpCacheTypeStructure (\r | |
323 | IN UINT8* Ptr,\r | |
324 | IN UINT8 Length\r | |
325 | )\r | |
326 | {\r | |
327 | ParseAcpi (\r | |
328 | TRUE,\r | |
329 | 2,\r | |
330 | "Cache Type Structure",\r | |
331 | Ptr,\r | |
332 | Length,\r | |
333 | PARSER_PARAMS (CacheTypeStructureParser)\r | |
334 | );\r | |
335 | }\r | |
336 | \r | |
337 | /**\r | |
338 | This function parses the ID Structure (Type 2).\r | |
339 | \r | |
340 | @param [in] Ptr Pointer to the start of the ID Structure data.\r | |
341 | @param [in] Length Length of the ID Structure.\r | |
342 | **/\r | |
343 | STATIC\r | |
344 | VOID\r | |
345 | DumpIDStructure (\r | |
346 | IN UINT8* Ptr,\r | |
347 | IN UINT8 Length\r | |
348 | )\r | |
349 | {\r | |
350 | ParseAcpi (\r | |
351 | TRUE,\r | |
352 | 2,\r | |
353 | "ID Structure",\r | |
354 | Ptr,\r | |
355 | Length,\r | |
356 | PARSER_PARAMS (IdStructureParser)\r | |
357 | );\r | |
358 | }\r | |
359 | \r | |
360 | /**\r | |
361 | This function parses the ACPI PPTT table.\r | |
362 | When trace is enabled this function parses the PPTT table and\r | |
363 | traces the ACPI table fields.\r | |
364 | \r | |
365 | This function parses the following processor topology structures:\r | |
366 | - Processor hierarchy node structure (Type 0)\r | |
367 | - Cache Type Structure (Type 1)\r | |
368 | - ID structure (Type 2)\r | |
369 | \r | |
370 | This function also performs validation of the ACPI table fields.\r | |
371 | \r | |
372 | @param [in] Trace If TRUE, trace the ACPI fields.\r | |
373 | @param [in] Ptr Pointer to the start of the buffer.\r | |
374 | @param [in] AcpiTableLength Length of the ACPI table.\r | |
375 | @param [in] AcpiTableRevision Revision of the ACPI table.\r | |
376 | **/\r | |
377 | VOID\r | |
378 | EFIAPI\r | |
379 | ParseAcpiPptt (\r | |
380 | IN BOOLEAN Trace,\r | |
381 | IN UINT8* Ptr,\r | |
382 | IN UINT32 AcpiTableLength,\r | |
383 | IN UINT8 AcpiTableRevision\r | |
384 | )\r | |
385 | {\r | |
386 | UINT32 Offset;\r | |
387 | UINT8* ProcessorTopologyStructurePtr;\r | |
388 | \r | |
389 | if (!Trace) {\r | |
390 | return;\r | |
391 | }\r | |
392 | \r | |
393 | Offset = ParseAcpi (\r | |
394 | TRUE,\r | |
395 | 0,\r | |
396 | "PPTT",\r | |
397 | Ptr,\r | |
398 | AcpiTableLength,\r | |
399 | PARSER_PARAMS (PpttParser)\r | |
400 | );\r | |
84a534b4 | 401 | \r |
d4d2fdf2 KK |
402 | ProcessorTopologyStructurePtr = Ptr + Offset;\r |
403 | \r | |
404 | while (Offset < AcpiTableLength) {\r | |
405 | // Parse Processor Hierarchy Node Structure to obtain Type and Length.\r | |
406 | ParseAcpi (\r | |
407 | FALSE,\r | |
408 | 0,\r | |
409 | NULL,\r | |
410 | ProcessorTopologyStructurePtr,\r | |
5f066122 | 411 | AcpiTableLength - Offset,\r |
d4d2fdf2 KK |
412 | PARSER_PARAMS (ProcessorTopologyStructureHeaderParser)\r |
413 | );\r | |
414 | \r | |
84a534b4 KK |
415 | // Check if the values used to control the parsing logic have been\r |
416 | // successfully read.\r | |
417 | if ((ProcessorTopologyStructureType == NULL) ||\r | |
418 | (ProcessorTopologyStructureLength == NULL)) {\r | |
419 | IncrementErrorCount ();\r | |
420 | Print (\r | |
421 | L"ERROR: Insufficient remaining table buffer length to read the " \\r | |
422 | L"processor topology structure header. Length = %d.\n",\r | |
423 | AcpiTableLength - Offset\r | |
424 | );\r | |
425 | return;\r | |
426 | }\r | |
427 | \r | |
b8504826 KK |
428 | // Validate Processor Topology Structure length\r |
429 | if ((*ProcessorTopologyStructureLength == 0) ||\r | |
430 | ((Offset + (*ProcessorTopologyStructureLength)) > AcpiTableLength)) {\r | |
d4d2fdf2 KK |
431 | IncrementErrorCount ();\r |
432 | Print (\r | |
b8504826 KK |
433 | L"ERROR: Invalid Processor Topology Structure length. " \\r |
434 | L"Length = %d. Offset = %d. AcpiTableLength = %d.\n",\r | |
5f066122 | 435 | *ProcessorTopologyStructureLength,\r |
b8504826 KK |
436 | Offset,\r |
437 | AcpiTableLength\r | |
d4d2fdf2 | 438 | );\r |
5f066122 | 439 | return;\r |
d4d2fdf2 KK |
440 | }\r |
441 | \r | |
442 | PrintFieldName (2, L"* Structure Offset *");\r | |
443 | Print (L"0x%x\n", Offset);\r | |
444 | \r | |
445 | switch (*ProcessorTopologyStructureType) {\r | |
446 | case EFI_ACPI_6_2_PPTT_TYPE_PROCESSOR:\r | |
447 | DumpProcessorHierarchyNodeStructure (\r | |
448 | ProcessorTopologyStructurePtr,\r | |
449 | *ProcessorTopologyStructureLength\r | |
450 | );\r | |
451 | break;\r | |
452 | case EFI_ACPI_6_2_PPTT_TYPE_CACHE:\r | |
453 | DumpCacheTypeStructure (\r | |
454 | ProcessorTopologyStructurePtr,\r | |
455 | *ProcessorTopologyStructureLength\r | |
456 | );\r | |
457 | break;\r | |
458 | case EFI_ACPI_6_2_PPTT_TYPE_ID:\r | |
459 | DumpIDStructure (\r | |
460 | ProcessorTopologyStructurePtr,\r | |
461 | *ProcessorTopologyStructureLength\r | |
462 | );\r | |
463 | break;\r | |
464 | default:\r | |
465 | IncrementErrorCount ();\r | |
466 | Print (\r | |
467 | L"ERROR: Unknown processor topology structure:"\r | |
468 | L" Type = %d, Length = %d\n",\r | |
469 | *ProcessorTopologyStructureType,\r | |
470 | *ProcessorTopologyStructureLength\r | |
471 | );\r | |
472 | }\r | |
473 | \r | |
474 | ProcessorTopologyStructurePtr += *ProcessorTopologyStructureLength;\r | |
475 | Offset += *ProcessorTopologyStructureLength;\r | |
476 | } // while\r | |
477 | }\r |