hc
2024-02-20 102a0743326a03cd1a1202ceda21e175b7d3575c
kernel/drivers/acpi/tables.c
....@@ -1,22 +1,8 @@
1
+// SPDX-License-Identifier: GPL-2.0-or-later
12 /*
23 * acpi_tables.c - ACPI Boot-Time Table Parsing
34 *
45 * Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com>
5
- *
6
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
7
- *
8
- * This program is free software; you can redistribute it and/or modify
9
- * it under the terms of the GNU General Public License as published by
10
- * the Free Software Foundation; either version 2 of the License, or
11
- * (at your option) any later version.
12
- *
13
- * This program is distributed in the hope that it will be useful,
14
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
15
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16
- * GNU General Public License for more details.
17
- *
18
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
19
- *
206 */
217
228 /* Uncomment next line to get verbose printout */
....@@ -31,10 +17,10 @@
3117 #include <linux/irq.h>
3218 #include <linux/errno.h>
3319 #include <linux/acpi.h>
34
-#include <linux/bootmem.h>
35
-#include <linux/earlycpio.h>
3620 #include <linux/memblock.h>
21
+#include <linux/earlycpio.h>
3722 #include <linux/initrd.h>
23
+#include <linux/security.h>
3824 #include "internal.h"
3925
4026 #ifdef CONFIG_ACPI_CUSTOM_DSDT
....@@ -49,6 +35,16 @@
4935 static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata;
5036
5137 static int acpi_apic_instance __initdata;
38
+
39
+enum acpi_subtable_type {
40
+ ACPI_SUBTABLE_COMMON,
41
+ ACPI_SUBTABLE_HMAT,
42
+};
43
+
44
+struct acpi_subtable_entry {
45
+ union acpi_subtable_headers *hdr;
46
+ enum acpi_subtable_type type;
47
+};
5248
5349 /*
5450 * Disable table checksum verification for the early stage due to the size
....@@ -218,6 +214,50 @@
218214 }
219215 }
220216
217
+static unsigned long __init
218
+acpi_get_entry_type(struct acpi_subtable_entry *entry)
219
+{
220
+ switch (entry->type) {
221
+ case ACPI_SUBTABLE_COMMON:
222
+ return entry->hdr->common.type;
223
+ case ACPI_SUBTABLE_HMAT:
224
+ return entry->hdr->hmat.type;
225
+ }
226
+ return 0;
227
+}
228
+
229
+static unsigned long __init
230
+acpi_get_entry_length(struct acpi_subtable_entry *entry)
231
+{
232
+ switch (entry->type) {
233
+ case ACPI_SUBTABLE_COMMON:
234
+ return entry->hdr->common.length;
235
+ case ACPI_SUBTABLE_HMAT:
236
+ return entry->hdr->hmat.length;
237
+ }
238
+ return 0;
239
+}
240
+
241
+static unsigned long __init
242
+acpi_get_subtable_header_length(struct acpi_subtable_entry *entry)
243
+{
244
+ switch (entry->type) {
245
+ case ACPI_SUBTABLE_COMMON:
246
+ return sizeof(entry->hdr->common);
247
+ case ACPI_SUBTABLE_HMAT:
248
+ return sizeof(entry->hdr->hmat);
249
+ }
250
+ return 0;
251
+}
252
+
253
+static enum acpi_subtable_type __init
254
+acpi_get_subtable_type(char *id)
255
+{
256
+ if (strncmp(id, ACPI_SIG_HMAT, 4) == 0)
257
+ return ACPI_SUBTABLE_HMAT;
258
+ return ACPI_SUBTABLE_COMMON;
259
+}
260
+
221261 /**
222262 * acpi_parse_entries_array - for each proc_num find a suitable subtable
223263 *
....@@ -241,49 +281,35 @@
241281 * On success returns sum of all matching entries for all proc handlers.
242282 * Otherwise, -ENODEV or -EINVAL is returned.
243283 */
244
-static int __init
245
-acpi_parse_entries_array(char *id, unsigned long table_size,
284
+static int __init acpi_parse_entries_array(char *id, unsigned long table_size,
246285 struct acpi_table_header *table_header,
247286 struct acpi_subtable_proc *proc, int proc_num,
248287 unsigned int max_entries)
249288 {
250
- struct acpi_subtable_header *entry;
251
- unsigned long table_end;
289
+ struct acpi_subtable_entry entry;
290
+ unsigned long table_end, subtable_len, entry_len;
252291 int count = 0;
253292 int errs = 0;
254293 int i;
255
-
256
- if (acpi_disabled)
257
- return -ENODEV;
258
-
259
- if (!id)
260
- return -EINVAL;
261
-
262
- if (!table_size)
263
- return -EINVAL;
264
-
265
- if (!table_header) {
266
- pr_warn("%4.4s not present\n", id);
267
- return -ENODEV;
268
- }
269294
270295 table_end = (unsigned long)table_header + table_header->length;
271296
272297 /* Parse all entries looking for a match. */
273298
274
- entry = (struct acpi_subtable_header *)
299
+ entry.type = acpi_get_subtable_type(id);
300
+ entry.hdr = (union acpi_subtable_headers *)
275301 ((unsigned long)table_header + table_size);
302
+ subtable_len = acpi_get_subtable_header_length(&entry);
276303
277
- while (((unsigned long)entry) + sizeof(struct acpi_subtable_header) <
278
- table_end) {
304
+ while (((unsigned long)entry.hdr) + subtable_len < table_end) {
279305 if (max_entries && count >= max_entries)
280306 break;
281307
282308 for (i = 0; i < proc_num; i++) {
283
- if (entry->type != proc[i].id)
309
+ if (acpi_get_entry_type(&entry) != proc[i].id)
284310 continue;
285311 if (!proc[i].handler ||
286
- (!errs && proc[i].handler(entry, table_end))) {
312
+ (!errs && proc[i].handler(entry.hdr, table_end))) {
287313 errs++;
288314 continue;
289315 }
....@@ -298,13 +324,14 @@
298324 * If entry->length is 0, break from this loop to avoid
299325 * infinite loop.
300326 */
301
- if (entry->length == 0) {
327
+ entry_len = acpi_get_entry_length(&entry);
328
+ if (entry_len == 0) {
302329 pr_err("[%4.4s:0x%02x] Invalid zero length\n", id, proc->id);
303330 return -EINVAL;
304331 }
305332
306
- entry = (struct acpi_subtable_header *)
307
- ((unsigned long)entry + entry->length);
333
+ entry.hdr = (union acpi_subtable_headers *)
334
+ ((unsigned long)entry.hdr + entry_len);
308335 }
309336
310337 if (max_entries && count > max_entries) {
....@@ -315,8 +342,7 @@
315342 return errs ? -EINVAL : count;
316343 }
317344
318
-int __init
319
-acpi_table_parse_entries_array(char *id,
345
+int __init acpi_table_parse_entries_array(char *id,
320346 unsigned long table_size,
321347 struct acpi_subtable_proc *proc, int proc_num,
322348 unsigned int max_entries)
....@@ -329,6 +355,9 @@
329355 return -ENODEV;
330356
331357 if (!id)
358
+ return -EINVAL;
359
+
360
+ if (!table_size)
332361 return -EINVAL;
333362
334363 if (!strncmp(id, ACPI_SIG_MADT, 4))
....@@ -347,8 +376,7 @@
347376 return count;
348377 }
349378
350
-int __init
351
-acpi_table_parse_entries(char *id,
379
+int __init acpi_table_parse_entries(char *id,
352380 unsigned long table_size,
353381 int entry_id,
354382 acpi_tbl_entry_handler handler,
....@@ -363,8 +391,7 @@
363391 max_entries);
364392 }
365393
366
-int __init
367
-acpi_table_parse_madt(enum acpi_madt_type id,
394
+int __init acpi_table_parse_madt(enum acpi_madt_type id,
368395 acpi_tbl_entry_handler handler, unsigned int max_entries)
369396 {
370397 return acpi_table_parse_entries(ACPI_SIG_MADT,
....@@ -452,17 +479,18 @@
452479 }
453480
454481 /* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */
455
-static const char * const table_sigs[] = {
456
- ACPI_SIG_BERT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, ACPI_SIG_EINJ,
457
- ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, ACPI_SIG_MSCT,
458
- ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, ACPI_SIG_ASF,
459
- ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, ACPI_SIG_HPET,
460
- ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, ACPI_SIG_MCHI,
461
- ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, ACPI_SIG_TCPA,
462
- ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, ACPI_SIG_WDDT,
463
- ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, ACPI_SIG_PSDT,
464
- ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, ACPI_SIG_IORT,
465
- ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, NULL };
482
+static const char table_sigs[][ACPI_NAMESEG_SIZE] __initconst = {
483
+ ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT,
484
+ ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT,
485
+ ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT,
486
+ ACPI_SIG_ASF, ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR,
487
+ ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG,
488
+ ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI,
489
+ ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT,
490
+ ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT,
491
+ ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT,
492
+ ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT,
493
+ ACPI_SIG_NHLT };
466494
467495 #define ACPI_HEADER_SIZE sizeof(struct acpi_table_header)
468496
....@@ -474,13 +502,21 @@
474502
475503 void __init acpi_table_upgrade(void)
476504 {
477
- void *data = (void *)initrd_start;
478
- size_t size = initrd_end - initrd_start;
505
+ void *data;
506
+ size_t size;
479507 int sig, no, table_nr = 0, total_offset = 0;
480508 long offset = 0;
481509 struct acpi_table_header *table;
482510 char cpio_path[32] = "kernel/firmware/acpi/";
483511 struct cpio_data file;
512
+
513
+ if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) {
514
+ data = __initramfs_start;
515
+ size = __initramfs_size;
516
+ } else {
517
+ data = (void *)initrd_start;
518
+ size = initrd_end - initrd_start;
519
+ }
484520
485521 if (data == NULL || size == 0)
486522 return;
....@@ -501,11 +537,11 @@
501537
502538 table = file.data;
503539
504
- for (sig = 0; table_sigs[sig]; sig++)
540
+ for (sig = 0; sig < ARRAY_SIZE(table_sigs); sig++)
505541 if (!memcmp(table->signature, table_sigs[sig], 4))
506542 break;
507543
508
- if (!table_sigs[sig]) {
544
+ if (sig >= ARRAY_SIZE(table_sigs)) {
509545 pr_err("ACPI OVERRIDE: Unknown signature [%s%s]\n",
510546 cpio_path, file.name);
511547 continue;
....@@ -531,6 +567,11 @@
531567 }
532568 if (table_nr == 0)
533569 return;
570
+
571
+ if (security_locked_down(LOCKDOWN_ACPI_TABLES)) {
572
+ pr_notice("kernel is locked down, ignoring table override\n");
573
+ return;
574
+ }
534575
535576 acpi_tables_addr =
536577 memblock_find_in_range(0, ACPI_TABLE_UPGRADE_MAX_PHYS,
....@@ -663,8 +704,8 @@
663704 table_length = table->length;
664705
665706 /* Skip RSDT/XSDT which should only be used for override */
666
- if (ACPI_COMPARE_NAME(table->signature, ACPI_SIG_RSDT) ||
667
- ACPI_COMPARE_NAME(table->signature, ACPI_SIG_XSDT)) {
707
+ if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_RSDT) ||
708
+ ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_XSDT)) {
668709 acpi_os_unmap_memory(table, ACPI_HEADER_SIZE);
669710 goto next_table;
670711 }
....@@ -713,8 +754,12 @@
713754 table_length);
714755 }
715756
716
-acpi_status
717
-acpi_os_table_override(struct acpi_table_header *existing_table,
757
+#ifdef CONFIG_ACPI_CUSTOM_DSDT
758
+static void *amlcode __attribute__ ((weakref("AmlCode")));
759
+static void *dsdt_amlcode __attribute__ ((weakref("dsdt_aml_code")));
760
+#endif
761
+
762
+acpi_status acpi_os_table_override(struct acpi_table_header *existing_table,
718763 struct acpi_table_header **new_table)
719764 {
720765 if (!existing_table || !new_table)
....@@ -723,8 +768,11 @@
723768 *new_table = NULL;
724769
725770 #ifdef CONFIG_ACPI_CUSTOM_DSDT
726
- if (strncmp(existing_table->signature, "DSDT", 4) == 0)
727
- *new_table = (struct acpi_table_header *)AmlCode;
771
+ if (!strncmp(existing_table->signature, "DSDT", 4)) {
772
+ *new_table = (struct acpi_table_header *)&amlcode;
773
+ if (!(*new_table))
774
+ *new_table = (struct acpi_table_header *)&dsdt_amlcode;
775
+ }
728776 #endif
729777 if (*new_table != NULL)
730778 acpi_table_taint(existing_table);
....@@ -809,7 +857,6 @@
809857
810858 return 0;
811859 }
812
-
813860 early_param("acpi_apic_instance", acpi_parse_apic_instance);
814861
815862 static int __init acpi_force_table_verification_setup(char *s)
....@@ -818,7 +865,6 @@
818865
819866 return 0;
820867 }
821
-
822868 early_param("acpi_force_table_verification", acpi_force_table_verification_setup);
823869
824870 static int __init acpi_force_32bit_fadt_addr(char *s)
....@@ -828,5 +874,4 @@
828874
829875 return 0;
830876 }
831
-
832877 early_param("acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr);