| 1 | // SPDX-License-Identifier: GPL-2.0-or-later | 
|---|
| 2 | /* | 
|---|
| 3 | *  acpi_tables.c - ACPI Boot-Time Table Parsing | 
|---|
| 4 | * | 
|---|
| 5 | *  Copyright (C) 2001 Paul Diefenbaugh <paul.s.diefenbaugh@intel.com> | 
|---|
| 6 | */ | 
|---|
| 7 |  | 
|---|
| 8 | /* Uncomment next line to get verbose printout */ | 
|---|
| 9 | /* #define DEBUG */ | 
|---|
| 10 | #define pr_fmt(fmt) "ACPI: " fmt | 
|---|
| 11 |  | 
|---|
| 12 | #include <linux/init.h> | 
|---|
| 13 | #include <linux/kernel.h> | 
|---|
| 14 | #include <linux/smp.h> | 
|---|
| 15 | #include <linux/string.h> | 
|---|
| 16 | #include <linux/types.h> | 
|---|
| 17 | #include <linux/irq.h> | 
|---|
| 18 | #include <linux/errno.h> | 
|---|
| 19 | #include <linux/acpi.h> | 
|---|
| 20 | #include <linux/memblock.h> | 
|---|
| 21 | #include <linux/earlycpio.h> | 
|---|
| 22 | #include <linux/initrd.h> | 
|---|
| 23 | #include <linux/security.h> | 
|---|
| 24 | #include <linux/kmemleak.h> | 
|---|
| 25 | #include "internal.h" | 
|---|
| 26 |  | 
|---|
| 27 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 
|---|
| 28 | #include CONFIG_ACPI_CUSTOM_DSDT_FILE | 
|---|
| 29 | #endif | 
|---|
| 30 |  | 
|---|
| 31 | #define ACPI_MAX_TABLES		128 | 
|---|
| 32 |  | 
|---|
| 33 | static char *mps_inti_flags_polarity[] = { "dfl", "high", "res", "low"}; | 
|---|
| 34 | static char *mps_inti_flags_trigger[] = { "dfl", "edge", "res", "level"}; | 
|---|
| 35 |  | 
|---|
| 36 | static struct acpi_table_desc initial_tables[ACPI_MAX_TABLES] __initdata; | 
|---|
| 37 |  | 
|---|
| 38 | static int acpi_apic_instance __initdata_or_acpilib; | 
|---|
| 39 |  | 
|---|
| 40 | /* | 
|---|
| 41 | * Disable table checksum verification for the early stage due to the size | 
|---|
| 42 | * limitation of the current x86 early mapping implementation. | 
|---|
| 43 | */ | 
|---|
| 44 | static bool acpi_verify_table_checksum __initdata_or_acpilib = false; | 
|---|
| 45 |  | 
|---|
| 46 | void acpi_table_print_madt_entry(struct acpi_subtable_header *) | 
|---|
| 47 | { | 
|---|
| 48 | if (!header) | 
|---|
| 49 | return; | 
|---|
| 50 |  | 
|---|
| 51 | switch (header->type) { | 
|---|
| 52 |  | 
|---|
| 53 | case ACPI_MADT_TYPE_LOCAL_APIC: | 
|---|
| 54 | { | 
|---|
| 55 | struct acpi_madt_local_apic *p = | 
|---|
| 56 | (struct acpi_madt_local_apic *)header; | 
|---|
| 57 | pr_debug( "LAPIC (acpi_id[0x%02x] lapic_id[0x%02x] %s)\n", | 
|---|
| 58 | p->processor_id, p->id, | 
|---|
| 59 | str_enabled_disabled(p->lapic_flags & ACPI_MADT_ENABLED)); | 
|---|
| 60 | } | 
|---|
| 61 | break; | 
|---|
| 62 |  | 
|---|
| 63 | case ACPI_MADT_TYPE_LOCAL_X2APIC: | 
|---|
| 64 | { | 
|---|
| 65 | struct acpi_madt_local_x2apic *p = | 
|---|
| 66 | (struct acpi_madt_local_x2apic *)header; | 
|---|
| 67 | pr_debug( "X2APIC (apic_id[0x%02x] uid[0x%02x] %s)\n", | 
|---|
| 68 | p->local_apic_id, p->uid, | 
|---|
| 69 | str_enabled_disabled(p->lapic_flags & ACPI_MADT_ENABLED)); | 
|---|
| 70 | } | 
|---|
| 71 | break; | 
|---|
| 72 |  | 
|---|
| 73 | case ACPI_MADT_TYPE_IO_APIC: | 
|---|
| 74 | { | 
|---|
| 75 | struct acpi_madt_io_apic *p = | 
|---|
| 76 | (struct acpi_madt_io_apic *)header; | 
|---|
| 77 | pr_debug( "IOAPIC (id[0x%02x] address[0x%08x] gsi_base[%d])\n", | 
|---|
| 78 | p->id, p->address, p->global_irq_base); | 
|---|
| 79 | } | 
|---|
| 80 | break; | 
|---|
| 81 |  | 
|---|
| 82 | case ACPI_MADT_TYPE_INTERRUPT_OVERRIDE: | 
|---|
| 83 | { | 
|---|
| 84 | struct acpi_madt_interrupt_override *p = | 
|---|
| 85 | (struct acpi_madt_interrupt_override *)header; | 
|---|
| 86 | pr_info( "INT_SRC_OVR (bus %d bus_irq %d global_irq %d %s %s)\n", | 
|---|
| 87 | p->bus, p->source_irq, p->global_irq, | 
|---|
| 88 | mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], | 
|---|
| 89 | mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2]); | 
|---|
| 90 | if (p->inti_flags  & | 
|---|
| 91 | ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)) | 
|---|
| 92 | pr_info( "INT_SRC_OVR unexpected reserved flags: 0x%x\n", | 
|---|
| 93 | p->inti_flags  & | 
|---|
| 94 | ~(ACPI_MADT_POLARITY_MASK | ACPI_MADT_TRIGGER_MASK)); | 
|---|
| 95 | } | 
|---|
| 96 | break; | 
|---|
| 97 |  | 
|---|
| 98 | case ACPI_MADT_TYPE_NMI_SOURCE: | 
|---|
| 99 | { | 
|---|
| 100 | struct acpi_madt_nmi_source *p = | 
|---|
| 101 | (struct acpi_madt_nmi_source *)header; | 
|---|
| 102 | pr_info( "NMI_SRC (%s %s global_irq %d)\n", | 
|---|
| 103 | mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], | 
|---|
| 104 | mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], | 
|---|
| 105 | p->global_irq); | 
|---|
| 106 | } | 
|---|
| 107 | break; | 
|---|
| 108 |  | 
|---|
| 109 | case ACPI_MADT_TYPE_LOCAL_APIC_NMI: | 
|---|
| 110 | { | 
|---|
| 111 | struct acpi_madt_local_apic_nmi *p = | 
|---|
| 112 | (struct acpi_madt_local_apic_nmi *)header; | 
|---|
| 113 | pr_info( "LAPIC_NMI (acpi_id[0x%02x] %s %s lint[0x%x])\n", | 
|---|
| 114 | p->processor_id, | 
|---|
| 115 | mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK	], | 
|---|
| 116 | mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], | 
|---|
| 117 | p->lint); | 
|---|
| 118 | } | 
|---|
| 119 | break; | 
|---|
| 120 |  | 
|---|
| 121 | case ACPI_MADT_TYPE_LOCAL_X2APIC_NMI: | 
|---|
| 122 | { | 
|---|
| 123 | u16 polarity, trigger; | 
|---|
| 124 | struct acpi_madt_local_x2apic_nmi *p = | 
|---|
| 125 | (struct acpi_madt_local_x2apic_nmi *)header; | 
|---|
| 126 |  | 
|---|
| 127 | polarity = p->inti_flags & ACPI_MADT_POLARITY_MASK; | 
|---|
| 128 | trigger = (p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2; | 
|---|
| 129 |  | 
|---|
| 130 | pr_info( "X2APIC_NMI (uid[0x%02x] %s %s lint[0x%x])\n", | 
|---|
| 131 | p->uid, | 
|---|
| 132 | mps_inti_flags_polarity[polarity], | 
|---|
| 133 | mps_inti_flags_trigger[trigger], | 
|---|
| 134 | p->lint); | 
|---|
| 135 | } | 
|---|
| 136 | break; | 
|---|
| 137 |  | 
|---|
| 138 | case ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE: | 
|---|
| 139 | { | 
|---|
| 140 | struct acpi_madt_local_apic_override *p = | 
|---|
| 141 | (struct acpi_madt_local_apic_override *)header; | 
|---|
| 142 | pr_info( "LAPIC_ADDR_OVR (address[0x%llx])\n", | 
|---|
| 143 | p->address); | 
|---|
| 144 | } | 
|---|
| 145 | break; | 
|---|
| 146 |  | 
|---|
| 147 | case ACPI_MADT_TYPE_IO_SAPIC: | 
|---|
| 148 | { | 
|---|
| 149 | struct acpi_madt_io_sapic *p = | 
|---|
| 150 | (struct acpi_madt_io_sapic *)header; | 
|---|
| 151 | pr_debug( "IOSAPIC (id[0x%x] address[%p] gsi_base[%d])\n", | 
|---|
| 152 | p->id, (void *)(unsigned long)p->address, | 
|---|
| 153 | p->global_irq_base); | 
|---|
| 154 | } | 
|---|
| 155 | break; | 
|---|
| 156 |  | 
|---|
| 157 | case ACPI_MADT_TYPE_LOCAL_SAPIC: | 
|---|
| 158 | { | 
|---|
| 159 | struct acpi_madt_local_sapic *p = | 
|---|
| 160 | (struct acpi_madt_local_sapic *)header; | 
|---|
| 161 | pr_debug( "LSAPIC (acpi_id[0x%02x] lsapic_id[0x%02x] lsapic_eid[0x%02x] %s)\n", | 
|---|
| 162 | p->processor_id, p->id, p->eid, | 
|---|
| 163 | str_enabled_disabled(p->lapic_flags & ACPI_MADT_ENABLED)); | 
|---|
| 164 | } | 
|---|
| 165 | break; | 
|---|
| 166 |  | 
|---|
| 167 | case ACPI_MADT_TYPE_INTERRUPT_SOURCE: | 
|---|
| 168 | { | 
|---|
| 169 | struct acpi_madt_interrupt_source *p = | 
|---|
| 170 | (struct acpi_madt_interrupt_source *)header; | 
|---|
| 171 | pr_info( "PLAT_INT_SRC (%s %s type[0x%x] id[0x%04x] eid[0x%x] iosapic_vector[0x%x] global_irq[0x%x]\n", | 
|---|
| 172 | mps_inti_flags_polarity[p->inti_flags & ACPI_MADT_POLARITY_MASK], | 
|---|
| 173 | mps_inti_flags_trigger[(p->inti_flags & ACPI_MADT_TRIGGER_MASK) >> 2], | 
|---|
| 174 | p->type, p->id, p->eid, p->io_sapic_vector, | 
|---|
| 175 | p->global_irq); | 
|---|
| 176 | } | 
|---|
| 177 | break; | 
|---|
| 178 |  | 
|---|
| 179 | case ACPI_MADT_TYPE_GENERIC_INTERRUPT: | 
|---|
| 180 | { | 
|---|
| 181 | struct acpi_madt_generic_interrupt *p = | 
|---|
| 182 | (struct acpi_madt_generic_interrupt *)header; | 
|---|
| 183 | pr_debug( "GICC (acpi_id[0x%04x] address[%llx] MPIDR[0x%llx] %s)\n", | 
|---|
| 184 | p->uid, p->base_address, | 
|---|
| 185 | p->arm_mpidr, | 
|---|
| 186 | str_enabled_disabled(p->flags & ACPI_MADT_ENABLED)); | 
|---|
| 187 |  | 
|---|
| 188 | } | 
|---|
| 189 | break; | 
|---|
| 190 |  | 
|---|
| 191 | case ACPI_MADT_TYPE_GENERIC_DISTRIBUTOR: | 
|---|
| 192 | { | 
|---|
| 193 | struct acpi_madt_generic_distributor *p = | 
|---|
| 194 | (struct acpi_madt_generic_distributor *)header; | 
|---|
| 195 | pr_debug( "GIC Distributor (gic_id[0x%04x] address[%llx] gsi_base[%d])\n", | 
|---|
| 196 | p->gic_id, p->base_address, | 
|---|
| 197 | p->global_irq_base); | 
|---|
| 198 | } | 
|---|
| 199 | break; | 
|---|
| 200 |  | 
|---|
| 201 | case ACPI_MADT_TYPE_MULTIPROC_WAKEUP: | 
|---|
| 202 | { | 
|---|
| 203 | struct acpi_madt_multiproc_wakeup *p = | 
|---|
| 204 | (struct acpi_madt_multiproc_wakeup *)header; | 
|---|
| 205 | u64 reset_vector = 0; | 
|---|
| 206 |  | 
|---|
| 207 | if (p->version >= ACPI_MADT_MP_WAKEUP_VERSION_V1) | 
|---|
| 208 | reset_vector = p->reset_vector; | 
|---|
| 209 |  | 
|---|
| 210 | pr_debug( "MP Wakeup (version[%d], mailbox[%#llx], reset[%#llx])\n", | 
|---|
| 211 | p->version, p->mailbox_address, reset_vector); | 
|---|
| 212 | } | 
|---|
| 213 | break; | 
|---|
| 214 |  | 
|---|
| 215 | case ACPI_MADT_TYPE_CORE_PIC: | 
|---|
| 216 | { | 
|---|
| 217 | struct acpi_madt_core_pic *p = (struct acpi_madt_core_pic *)header; | 
|---|
| 218 |  | 
|---|
| 219 | pr_debug( "CORE PIC (processor_id[0x%02x] core_id[0x%02x] %s)\n", | 
|---|
| 220 | p->processor_id, p->core_id, | 
|---|
| 221 | str_enabled_disabled(p->flags & ACPI_MADT_ENABLED)); | 
|---|
| 222 | } | 
|---|
| 223 | break; | 
|---|
| 224 |  | 
|---|
| 225 | case ACPI_MADT_TYPE_RINTC: | 
|---|
| 226 | { | 
|---|
| 227 | struct acpi_madt_rintc *p = (struct acpi_madt_rintc *)header; | 
|---|
| 228 |  | 
|---|
| 229 | pr_debug( "RISC-V INTC (acpi_uid[0x%04x] hart_id[0x%llx] %s)\n", | 
|---|
| 230 | p->uid, p->hart_id, | 
|---|
| 231 | str_enabled_disabled(p->flags & ACPI_MADT_ENABLED)); | 
|---|
| 232 | } | 
|---|
| 233 | break; | 
|---|
| 234 |  | 
|---|
| 235 | default: | 
|---|
| 236 | pr_warn( "Found unsupported MADT entry (type = 0x%x)\n", | 
|---|
| 237 | header->type); | 
|---|
| 238 | break; | 
|---|
| 239 | } | 
|---|
| 240 | } | 
|---|
| 241 |  | 
|---|
| 242 | int __init_or_acpilib acpi_table_parse_entries_array( | 
|---|
| 243 | char *id, unsigned long table_size, struct acpi_subtable_proc *proc, | 
|---|
| 244 | int proc_num, unsigned int max_entries) | 
|---|
| 245 | { | 
|---|
| 246 | struct acpi_table_header * = NULL; | 
|---|
| 247 | int count; | 
|---|
| 248 | u32 instance = 0; | 
|---|
| 249 |  | 
|---|
| 250 | if (acpi_disabled) | 
|---|
| 251 | return -ENODEV; | 
|---|
| 252 |  | 
|---|
| 253 | if (!id) | 
|---|
| 254 | return -EINVAL; | 
|---|
| 255 |  | 
|---|
| 256 | if (!table_size) | 
|---|
| 257 | return -EINVAL; | 
|---|
| 258 |  | 
|---|
| 259 | if (!strncmp(id, ACPI_SIG_MADT, 4)) | 
|---|
| 260 | instance = acpi_apic_instance; | 
|---|
| 261 |  | 
|---|
| 262 | acpi_get_table(signature: id, instance, out_table: &table_header); | 
|---|
| 263 | if (!table_header) { | 
|---|
| 264 | pr_debug( "%4.4s not present\n", id); | 
|---|
| 265 | return -ENODEV; | 
|---|
| 266 | } | 
|---|
| 267 |  | 
|---|
| 268 | count = acpi_parse_entries_array(id, table_size, | 
|---|
| 269 | table_header: (union fw_table_header *)table_header, | 
|---|
| 270 | max_length: 0, proc, proc_num, max_entries); | 
|---|
| 271 |  | 
|---|
| 272 | acpi_put_table(table: table_header); | 
|---|
| 273 | return count; | 
|---|
| 274 | } | 
|---|
| 275 |  | 
|---|
| 276 | static int __init_or_acpilib __acpi_table_parse_entries( | 
|---|
| 277 | char *id, unsigned long table_size, int entry_id, | 
|---|
| 278 | acpi_tbl_entry_handler handler, acpi_tbl_entry_handler_arg handler_arg, | 
|---|
| 279 | void *arg, unsigned int max_entries) | 
|---|
| 280 | { | 
|---|
| 281 | struct acpi_subtable_proc proc = { | 
|---|
| 282 | .id		= entry_id, | 
|---|
| 283 | .handler	= handler, | 
|---|
| 284 | .handler_arg	= handler_arg, | 
|---|
| 285 | .arg		= arg, | 
|---|
| 286 | }; | 
|---|
| 287 |  | 
|---|
| 288 | return acpi_table_parse_entries_array(id, table_size, proc: &proc, proc_num: 1, | 
|---|
| 289 | max_entries); | 
|---|
| 290 | } | 
|---|
| 291 |  | 
|---|
| 292 | int __init_or_acpilib | 
|---|
| 293 | acpi_table_parse_cedt(enum acpi_cedt_type id, | 
|---|
| 294 | acpi_tbl_entry_handler_arg handler_arg, void *arg) | 
|---|
| 295 | { | 
|---|
| 296 | return __acpi_table_parse_entries(ACPI_SIG_CEDT, | 
|---|
| 297 | table_size: sizeof(struct acpi_table_cedt), entry_id: id, | 
|---|
| 298 | NULL, handler_arg, arg, max_entries: 0); | 
|---|
| 299 | } | 
|---|
| 300 | EXPORT_SYMBOL_ACPI_LIB(acpi_table_parse_cedt); | 
|---|
| 301 |  | 
|---|
| 302 | int __init acpi_table_parse_entries(char *id, unsigned long table_size, | 
|---|
| 303 | int entry_id, | 
|---|
| 304 | acpi_tbl_entry_handler handler, | 
|---|
| 305 | unsigned int max_entries) | 
|---|
| 306 | { | 
|---|
| 307 | return __acpi_table_parse_entries(id, table_size, entry_id, handler, | 
|---|
| 308 | NULL, NULL, max_entries); | 
|---|
| 309 | } | 
|---|
| 310 |  | 
|---|
| 311 | int __init acpi_table_parse_madt(enum acpi_madt_type id, | 
|---|
| 312 | acpi_tbl_entry_handler handler, unsigned int max_entries) | 
|---|
| 313 | { | 
|---|
| 314 | return acpi_table_parse_entries(ACPI_SIG_MADT, | 
|---|
| 315 | table_size: sizeof(struct acpi_table_madt), entry_id: id, | 
|---|
| 316 | handler, max_entries); | 
|---|
| 317 | } | 
|---|
| 318 |  | 
|---|
| 319 | /** | 
|---|
| 320 | * acpi_table_parse - find table with @id, run @handler on it | 
|---|
| 321 | * @id: table id to find | 
|---|
| 322 | * @handler: handler to run | 
|---|
| 323 | * | 
|---|
| 324 | * Scan the ACPI System Descriptor Table (STD) for a table matching @id, | 
|---|
| 325 | * run @handler on it. | 
|---|
| 326 | * | 
|---|
| 327 | * Return 0 if table found, -errno if not. | 
|---|
| 328 | */ | 
|---|
| 329 | int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) | 
|---|
| 330 | { | 
|---|
| 331 | struct acpi_table_header *table = NULL; | 
|---|
| 332 |  | 
|---|
| 333 | if (acpi_disabled) | 
|---|
| 334 | return -ENODEV; | 
|---|
| 335 |  | 
|---|
| 336 | if (!id || !handler) | 
|---|
| 337 | return -EINVAL; | 
|---|
| 338 |  | 
|---|
| 339 | if (strncmp(id, ACPI_SIG_MADT, 4) == 0) | 
|---|
| 340 | acpi_get_table(signature: id, instance: acpi_apic_instance, out_table: &table); | 
|---|
| 341 | else | 
|---|
| 342 | acpi_get_table(signature: id, instance: 0, out_table: &table); | 
|---|
| 343 |  | 
|---|
| 344 | if (table) { | 
|---|
| 345 | handler(table); | 
|---|
| 346 | acpi_put_table(table); | 
|---|
| 347 | return 0; | 
|---|
| 348 | } else | 
|---|
| 349 | return -ENODEV; | 
|---|
| 350 | } | 
|---|
| 351 |  | 
|---|
| 352 | /* | 
|---|
| 353 | * The BIOS is supposed to supply a single APIC/MADT, | 
|---|
| 354 | * but some report two.  Provide a knob to use either. | 
|---|
| 355 | * (don't you wish instance 0 and 1 were not the same?) | 
|---|
| 356 | */ | 
|---|
| 357 | static void __init check_multiple_madt(void) | 
|---|
| 358 | { | 
|---|
| 359 | struct acpi_table_header *table = NULL; | 
|---|
| 360 |  | 
|---|
| 361 | acpi_get_table(ACPI_SIG_MADT, instance: 2, out_table: &table); | 
|---|
| 362 | if (table) { | 
|---|
| 363 | pr_warn( "BIOS bug: multiple APIC/MADT found, using %d\n", | 
|---|
| 364 | acpi_apic_instance); | 
|---|
| 365 | pr_warn( "If \"acpi_apic_instance=%d\" works better, " | 
|---|
| 366 | "notify linux-acpi@vger.kernel.org\n", | 
|---|
| 367 | acpi_apic_instance ? 0 : 2); | 
|---|
| 368 | acpi_put_table(table); | 
|---|
| 369 |  | 
|---|
| 370 | } else | 
|---|
| 371 | acpi_apic_instance = 0; | 
|---|
| 372 |  | 
|---|
| 373 | return; | 
|---|
| 374 | } | 
|---|
| 375 |  | 
|---|
| 376 | static void acpi_table_taint(struct acpi_table_header *table) | 
|---|
| 377 | { | 
|---|
| 378 | pr_warn( "Override [%4.4s-%8.8s], this is unsafe: tainting kernel\n", | 
|---|
| 379 | table->signature, table->oem_table_id); | 
|---|
| 380 | add_taint(TAINT_OVERRIDDEN_ACPI_TABLE, LOCKDEP_NOW_UNRELIABLE); | 
|---|
| 381 | } | 
|---|
| 382 |  | 
|---|
| 383 | #ifdef CONFIG_ACPI_TABLE_UPGRADE | 
|---|
| 384 | static u64 acpi_tables_addr; | 
|---|
| 385 | static int all_tables_size; | 
|---|
| 386 |  | 
|---|
| 387 | /* Copied from acpica/tbutils.c:acpi_tb_checksum() */ | 
|---|
| 388 | static u8 __init acpi_table_checksum(u8 *buffer, u32 length) | 
|---|
| 389 | { | 
|---|
| 390 | u8 sum = 0; | 
|---|
| 391 | u8 *end = buffer + length; | 
|---|
| 392 |  | 
|---|
| 393 | while (buffer < end) | 
|---|
| 394 | sum = (u8) (sum + *(buffer++)); | 
|---|
| 395 | return sum; | 
|---|
| 396 | } | 
|---|
| 397 |  | 
|---|
| 398 | /* All but ACPI_SIG_RSDP and ACPI_SIG_FACS: */ | 
|---|
| 399 | static const char table_sigs[][ACPI_NAMESEG_SIZE] __nonstring_array __initconst = { | 
|---|
| 400 | ACPI_SIG_BERT, ACPI_SIG_BGRT, ACPI_SIG_CPEP, ACPI_SIG_ECDT, | 
|---|
| 401 | ACPI_SIG_EINJ, ACPI_SIG_ERST, ACPI_SIG_HEST, ACPI_SIG_MADT, | 
|---|
| 402 | ACPI_SIG_MSCT, ACPI_SIG_SBST, ACPI_SIG_SLIT, ACPI_SIG_SRAT, | 
|---|
| 403 | ACPI_SIG_ASF,  ACPI_SIG_BOOT, ACPI_SIG_DBGP, ACPI_SIG_DMAR, | 
|---|
| 404 | ACPI_SIG_HPET, ACPI_SIG_IBFT, ACPI_SIG_IVRS, ACPI_SIG_MCFG, | 
|---|
| 405 | ACPI_SIG_MCHI, ACPI_SIG_SLIC, ACPI_SIG_SPCR, ACPI_SIG_SPMI, | 
|---|
| 406 | ACPI_SIG_TCPA, ACPI_SIG_UEFI, ACPI_SIG_WAET, ACPI_SIG_WDAT, | 
|---|
| 407 | ACPI_SIG_WDDT, ACPI_SIG_WDRT, ACPI_SIG_DSDT, ACPI_SIG_FADT, | 
|---|
| 408 | ACPI_SIG_PSDT, ACPI_SIG_RSDT, ACPI_SIG_XSDT, ACPI_SIG_SSDT, | 
|---|
| 409 | ACPI_SIG_IORT, ACPI_SIG_NFIT, ACPI_SIG_HMAT, ACPI_SIG_PPTT, | 
|---|
| 410 | ACPI_SIG_NHLT, ACPI_SIG_AEST, ACPI_SIG_CEDT, ACPI_SIG_AGDI, | 
|---|
| 411 | ACPI_SIG_NBFT, ACPI_SIG_SWFT}; | 
|---|
| 412 |  | 
|---|
| 413 | #define  sizeof(struct acpi_table_header) | 
|---|
| 414 |  | 
|---|
| 415 | #define NR_ACPI_INITRD_TABLES 64 | 
|---|
| 416 | static struct cpio_data __initdata acpi_initrd_files[NR_ACPI_INITRD_TABLES]; | 
|---|
| 417 | static DECLARE_BITMAP(acpi_initrd_installed, NR_ACPI_INITRD_TABLES); | 
|---|
| 418 |  | 
|---|
| 419 | #define MAP_CHUNK_SIZE   (NR_FIX_BTMAPS << PAGE_SHIFT) | 
|---|
| 420 |  | 
|---|
| 421 | void __init acpi_table_upgrade(void) | 
|---|
| 422 | { | 
|---|
| 423 | void *data; | 
|---|
| 424 | size_t size; | 
|---|
| 425 | int sig, no, table_nr = 0, total_offset = 0; | 
|---|
| 426 | long offset = 0; | 
|---|
| 427 | struct acpi_table_header *table; | 
|---|
| 428 | char cpio_path[32] = "kernel/firmware/acpi/"; | 
|---|
| 429 | struct cpio_data file; | 
|---|
| 430 |  | 
|---|
| 431 | if (IS_ENABLED(CONFIG_ACPI_TABLE_OVERRIDE_VIA_BUILTIN_INITRD)) { | 
|---|
| 432 | data = __initramfs_start; | 
|---|
| 433 | size = __initramfs_size; | 
|---|
| 434 | } else { | 
|---|
| 435 | data = (void *)initrd_start; | 
|---|
| 436 | size = initrd_end - initrd_start; | 
|---|
| 437 | } | 
|---|
| 438 |  | 
|---|
| 439 | if (data == NULL || size == 0) | 
|---|
| 440 | return; | 
|---|
| 441 |  | 
|---|
| 442 | for (no = 0; no < NR_ACPI_INITRD_TABLES; no++) { | 
|---|
| 443 | file = find_cpio_data(path: cpio_path, data, len: size, offset: &offset); | 
|---|
| 444 | if (!file.data) | 
|---|
| 445 | break; | 
|---|
| 446 |  | 
|---|
| 447 | data += offset; | 
|---|
| 448 | size -= offset; | 
|---|
| 449 |  | 
|---|
| 450 | if (file.size < sizeof(struct acpi_table_header)) { | 
|---|
| 451 | pr_err( "ACPI OVERRIDE: Table smaller than ACPI header [%s%s]\n", | 
|---|
| 452 | cpio_path, file.name); | 
|---|
| 453 | continue; | 
|---|
| 454 | } | 
|---|
| 455 |  | 
|---|
| 456 | table = file.data; | 
|---|
| 457 |  | 
|---|
| 458 | for (sig = 0; sig < ARRAY_SIZE(table_sigs); sig++) | 
|---|
| 459 | if (!memcmp(table->signature, table_sigs[sig], 4)) | 
|---|
| 460 | break; | 
|---|
| 461 |  | 
|---|
| 462 | if (sig >= ARRAY_SIZE(table_sigs)) { | 
|---|
| 463 | pr_err( "ACPI OVERRIDE: Unknown signature [%s%s]\n", | 
|---|
| 464 | cpio_path, file.name); | 
|---|
| 465 | continue; | 
|---|
| 466 | } | 
|---|
| 467 | if (file.size != table->length) { | 
|---|
| 468 | pr_err( "ACPI OVERRIDE: File length does not match table length [%s%s]\n", | 
|---|
| 469 | cpio_path, file.name); | 
|---|
| 470 | continue; | 
|---|
| 471 | } | 
|---|
| 472 | if (acpi_table_checksum(buffer: file.data, length: table->length)) { | 
|---|
| 473 | pr_err( "ACPI OVERRIDE: Bad table checksum [%s%s]\n", | 
|---|
| 474 | cpio_path, file.name); | 
|---|
| 475 | continue; | 
|---|
| 476 | } | 
|---|
| 477 |  | 
|---|
| 478 | pr_info( "%4.4s ACPI table found in initrd [%s%s][0x%x]\n", | 
|---|
| 479 | table->signature, cpio_path, file.name, table->length); | 
|---|
| 480 |  | 
|---|
| 481 | all_tables_size += table->length; | 
|---|
| 482 | acpi_initrd_files[table_nr].data = file.data; | 
|---|
| 483 | acpi_initrd_files[table_nr].size = file.size; | 
|---|
| 484 | table_nr++; | 
|---|
| 485 | } | 
|---|
| 486 | if (table_nr == 0) | 
|---|
| 487 | return; | 
|---|
| 488 |  | 
|---|
| 489 | if (security_locked_down(what: LOCKDOWN_ACPI_TABLES)) { | 
|---|
| 490 | pr_notice( "kernel is locked down, ignoring table override\n"); | 
|---|
| 491 | return; | 
|---|
| 492 | } | 
|---|
| 493 |  | 
|---|
| 494 | acpi_tables_addr = | 
|---|
| 495 | memblock_phys_alloc_range(size: all_tables_size, PAGE_SIZE, | 
|---|
| 496 | start: 0, ACPI_TABLE_UPGRADE_MAX_PHYS); | 
|---|
| 497 | if (!acpi_tables_addr) { | 
|---|
| 498 | WARN_ON(1); | 
|---|
| 499 | return; | 
|---|
| 500 | } | 
|---|
| 501 | /* | 
|---|
| 502 | * Only calling e820_add_reserve does not work and the | 
|---|
| 503 | * tables are invalid (memory got used) later. | 
|---|
| 504 | * memblock_reserve works as expected and the tables won't get modified. | 
|---|
| 505 | * But it's not enough on X86 because ioremap will | 
|---|
| 506 | * complain later (used by acpi_os_map_memory) that the pages | 
|---|
| 507 | * that should get mapped are not marked "reserved". | 
|---|
| 508 | * Both memblock_reserve and e820__range_add (via arch_reserve_mem_area) | 
|---|
| 509 | * works fine. | 
|---|
| 510 | */ | 
|---|
| 511 | arch_reserve_mem_area(addr: acpi_tables_addr, size: all_tables_size); | 
|---|
| 512 |  | 
|---|
| 513 | kmemleak_ignore_phys(phys: acpi_tables_addr); | 
|---|
| 514 |  | 
|---|
| 515 | /* | 
|---|
| 516 | * early_ioremap only can remap 256k one time. If we map all | 
|---|
| 517 | * tables one time, we will hit the limit. Need to map chunks | 
|---|
| 518 | * one by one during copying the same as that in relocate_initrd(). | 
|---|
| 519 | */ | 
|---|
| 520 | for (no = 0; no < table_nr; no++) { | 
|---|
| 521 | unsigned char *src_p = acpi_initrd_files[no].data; | 
|---|
| 522 | phys_addr_t size = acpi_initrd_files[no].size; | 
|---|
| 523 | phys_addr_t dest_addr = acpi_tables_addr + total_offset; | 
|---|
| 524 | phys_addr_t slop, clen; | 
|---|
| 525 | char *dest_p; | 
|---|
| 526 |  | 
|---|
| 527 | total_offset += size; | 
|---|
| 528 |  | 
|---|
| 529 | while (size) { | 
|---|
| 530 | slop = dest_addr & ~PAGE_MASK; | 
|---|
| 531 | clen = size; | 
|---|
| 532 | if (clen > MAP_CHUNK_SIZE - slop) | 
|---|
| 533 | clen = MAP_CHUNK_SIZE - slop; | 
|---|
| 534 | dest_p = early_memremap(phys_addr: dest_addr & PAGE_MASK, | 
|---|
| 535 | size: clen + slop); | 
|---|
| 536 | memcpy(to: dest_p + slop, from: src_p, len: clen); | 
|---|
| 537 | early_memunmap(addr: dest_p, size: clen + slop); | 
|---|
| 538 | src_p += clen; | 
|---|
| 539 | dest_addr += clen; | 
|---|
| 540 | size -= clen; | 
|---|
| 541 | } | 
|---|
| 542 | } | 
|---|
| 543 | } | 
|---|
| 544 |  | 
|---|
| 545 | static acpi_status | 
|---|
| 546 | acpi_table_initrd_override(struct acpi_table_header *existing_table, | 
|---|
| 547 | acpi_physical_address *address, u32 *length) | 
|---|
| 548 | { | 
|---|
| 549 | int table_offset = 0; | 
|---|
| 550 | int table_index = 0; | 
|---|
| 551 | struct acpi_table_header *table; | 
|---|
| 552 | u32 table_length; | 
|---|
| 553 |  | 
|---|
| 554 | *length = 0; | 
|---|
| 555 | *address = 0; | 
|---|
| 556 | if (!acpi_tables_addr) | 
|---|
| 557 | return AE_OK; | 
|---|
| 558 |  | 
|---|
| 559 | while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { | 
|---|
| 560 | table = acpi_os_map_memory(where: acpi_tables_addr + table_offset, | 
|---|
| 561 | ACPI_HEADER_SIZE); | 
|---|
| 562 | if (table_offset + table->length > all_tables_size) { | 
|---|
| 563 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 564 | WARN_ON(1); | 
|---|
| 565 | return AE_OK; | 
|---|
| 566 | } | 
|---|
| 567 |  | 
|---|
| 568 | table_length = table->length; | 
|---|
| 569 |  | 
|---|
| 570 | /* Only override tables matched */ | 
|---|
| 571 | if (memcmp(existing_table->signature, table->signature, 4) || | 
|---|
| 572 | memcmp(table->oem_id, existing_table->oem_id, | 
|---|
| 573 | ACPI_OEM_ID_SIZE) || | 
|---|
| 574 | memcmp(table->oem_table_id, existing_table->oem_table_id, | 
|---|
| 575 | ACPI_OEM_TABLE_ID_SIZE)) { | 
|---|
| 576 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 577 | goto next_table; | 
|---|
| 578 | } | 
|---|
| 579 | /* | 
|---|
| 580 | * Mark the table to avoid being used in | 
|---|
| 581 | * acpi_table_initrd_scan() and check the revision. | 
|---|
| 582 | */ | 
|---|
| 583 | if (test_and_set_bit(nr: table_index, addr: acpi_initrd_installed) || | 
|---|
| 584 | existing_table->oem_revision >= table->oem_revision) { | 
|---|
| 585 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 586 | goto next_table; | 
|---|
| 587 | } | 
|---|
| 588 |  | 
|---|
| 589 | *length = table_length; | 
|---|
| 590 | *address = acpi_tables_addr + table_offset; | 
|---|
| 591 | pr_info( "Table Upgrade: override [%4.4s-%6.6s-%8.8s]\n", | 
|---|
| 592 | table->signature, table->oem_id, | 
|---|
| 593 | table->oem_table_id); | 
|---|
| 594 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 595 | break; | 
|---|
| 596 |  | 
|---|
| 597 | next_table: | 
|---|
| 598 | table_offset += table_length; | 
|---|
| 599 | table_index++; | 
|---|
| 600 | } | 
|---|
| 601 | return AE_OK; | 
|---|
| 602 | } | 
|---|
| 603 |  | 
|---|
| 604 | static void __init acpi_table_initrd_scan(void) | 
|---|
| 605 | { | 
|---|
| 606 | int table_offset = 0; | 
|---|
| 607 | int table_index = 0; | 
|---|
| 608 | u32 table_length; | 
|---|
| 609 | struct acpi_table_header *table; | 
|---|
| 610 |  | 
|---|
| 611 | if (!acpi_tables_addr) | 
|---|
| 612 | return; | 
|---|
| 613 |  | 
|---|
| 614 | while (table_offset + ACPI_HEADER_SIZE <= all_tables_size) { | 
|---|
| 615 | table = acpi_os_map_memory(where: acpi_tables_addr + table_offset, | 
|---|
| 616 | ACPI_HEADER_SIZE); | 
|---|
| 617 | if (table_offset + table->length > all_tables_size) { | 
|---|
| 618 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 619 | WARN_ON(1); | 
|---|
| 620 | return; | 
|---|
| 621 | } | 
|---|
| 622 |  | 
|---|
| 623 | table_length = table->length; | 
|---|
| 624 |  | 
|---|
| 625 | /* Skip RSDT/XSDT which should only be used for override */ | 
|---|
| 626 | if (ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_RSDT) || | 
|---|
| 627 | ACPI_COMPARE_NAMESEG(table->signature, ACPI_SIG_XSDT)) { | 
|---|
| 628 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 629 | goto next_table; | 
|---|
| 630 | } | 
|---|
| 631 | /* | 
|---|
| 632 | * Mark the table to avoid being used in | 
|---|
| 633 | * acpi_table_initrd_override(). Though this is not possible | 
|---|
| 634 | * because override is disabled in acpi_install_physical_table(). | 
|---|
| 635 | */ | 
|---|
| 636 | if (test_and_set_bit(nr: table_index, addr: acpi_initrd_installed)) { | 
|---|
| 637 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 638 | goto next_table; | 
|---|
| 639 | } | 
|---|
| 640 |  | 
|---|
| 641 | pr_info( "Table Upgrade: install [%4.4s-%6.6s-%8.8s]\n", | 
|---|
| 642 | table->signature, table->oem_id, | 
|---|
| 643 | table->oem_table_id); | 
|---|
| 644 | acpi_os_unmap_memory(logical_address: table, ACPI_HEADER_SIZE); | 
|---|
| 645 | acpi_install_physical_table(address: acpi_tables_addr + table_offset); | 
|---|
| 646 | next_table: | 
|---|
| 647 | table_offset += table_length; | 
|---|
| 648 | table_index++; | 
|---|
| 649 | } | 
|---|
| 650 | } | 
|---|
| 651 | #else | 
|---|
| 652 | static acpi_status | 
|---|
| 653 | acpi_table_initrd_override(struct acpi_table_header *existing_table, | 
|---|
| 654 | acpi_physical_address *address, | 
|---|
| 655 | u32 *table_length) | 
|---|
| 656 | { | 
|---|
| 657 | *table_length = 0; | 
|---|
| 658 | *address = 0; | 
|---|
| 659 | return AE_OK; | 
|---|
| 660 | } | 
|---|
| 661 |  | 
|---|
| 662 | static void __init acpi_table_initrd_scan(void) | 
|---|
| 663 | { | 
|---|
| 664 | } | 
|---|
| 665 | #endif /* CONFIG_ACPI_TABLE_UPGRADE */ | 
|---|
| 666 |  | 
|---|
| 667 | acpi_status | 
|---|
| 668 | acpi_os_physical_table_override(struct acpi_table_header *existing_table, | 
|---|
| 669 | acpi_physical_address *address, | 
|---|
| 670 | u32 *table_length) | 
|---|
| 671 | { | 
|---|
| 672 | return acpi_table_initrd_override(existing_table, address, | 
|---|
| 673 | length: table_length); | 
|---|
| 674 | } | 
|---|
| 675 |  | 
|---|
| 676 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 
|---|
| 677 | static void *amlcode __attribute__ ((weakref( "AmlCode"))); | 
|---|
| 678 | static void *dsdt_amlcode __attribute__ ((weakref( "dsdt_aml_code"))); | 
|---|
| 679 | #endif | 
|---|
| 680 |  | 
|---|
| 681 | acpi_status acpi_os_table_override(struct acpi_table_header *existing_table, | 
|---|
| 682 | struct acpi_table_header **new_table) | 
|---|
| 683 | { | 
|---|
| 684 | if (!existing_table || !new_table) | 
|---|
| 685 | return AE_BAD_PARAMETER; | 
|---|
| 686 |  | 
|---|
| 687 | *new_table = NULL; | 
|---|
| 688 |  | 
|---|
| 689 | #ifdef CONFIG_ACPI_CUSTOM_DSDT | 
|---|
| 690 | if (!strncmp(existing_table->signature, "DSDT", 4)) { | 
|---|
| 691 | *new_table = (struct acpi_table_header *)&amlcode; | 
|---|
| 692 | if (!(*new_table)) | 
|---|
| 693 | *new_table = (struct acpi_table_header *)&dsdt_amlcode; | 
|---|
| 694 | } | 
|---|
| 695 | #endif | 
|---|
| 696 | if (*new_table != NULL) | 
|---|
| 697 | acpi_table_taint(table: existing_table); | 
|---|
| 698 | return AE_OK; | 
|---|
| 699 | } | 
|---|
| 700 |  | 
|---|
| 701 | /* | 
|---|
| 702 | * acpi_locate_initial_tables() | 
|---|
| 703 | * | 
|---|
| 704 | * Get the RSDP, then find and checksum all the ACPI tables. | 
|---|
| 705 | * | 
|---|
| 706 | * result: initial_tables[] is initialized, and points to | 
|---|
| 707 | * a list of ACPI tables. | 
|---|
| 708 | */ | 
|---|
| 709 | int __init acpi_locate_initial_tables(void) | 
|---|
| 710 | { | 
|---|
| 711 | acpi_status status; | 
|---|
| 712 |  | 
|---|
| 713 | if (acpi_verify_table_checksum) { | 
|---|
| 714 | pr_info( "Early table checksum verification enabled\n"); | 
|---|
| 715 | acpi_gbl_enable_table_validation = TRUE; | 
|---|
| 716 | } else { | 
|---|
| 717 | pr_info( "Early table checksum verification disabled\n"); | 
|---|
| 718 | acpi_gbl_enable_table_validation = FALSE; | 
|---|
| 719 | } | 
|---|
| 720 |  | 
|---|
| 721 | status = acpi_initialize_tables(initial_storage: initial_tables, ACPI_MAX_TABLES, allow_resize: 0); | 
|---|
| 722 | if (ACPI_FAILURE(status)) { | 
|---|
| 723 | const char *msg = acpi_format_exception(exception: status); | 
|---|
| 724 |  | 
|---|
| 725 | pr_warn( "Failed to initialize tables, status=0x%x (%s)", status, msg); | 
|---|
| 726 | return -EINVAL; | 
|---|
| 727 | } | 
|---|
| 728 |  | 
|---|
| 729 | return 0; | 
|---|
| 730 | } | 
|---|
| 731 |  | 
|---|
| 732 | void __init acpi_reserve_initial_tables(void) | 
|---|
| 733 | { | 
|---|
| 734 | int i; | 
|---|
| 735 |  | 
|---|
| 736 | for (i = 0; i < ACPI_MAX_TABLES; i++) { | 
|---|
| 737 | struct acpi_table_desc *table_desc = &initial_tables[i]; | 
|---|
| 738 | u64 start = table_desc->address; | 
|---|
| 739 | u64 size = table_desc->length; | 
|---|
| 740 |  | 
|---|
| 741 | if (!start || !size) | 
|---|
| 742 | break; | 
|---|
| 743 |  | 
|---|
| 744 | pr_info( "Reserving %4s table memory at [mem 0x%llx-0x%llx]\n", | 
|---|
| 745 | table_desc->signature.ascii, start, start + size - 1); | 
|---|
| 746 |  | 
|---|
| 747 | memblock_reserve(base: start, size); | 
|---|
| 748 | } | 
|---|
| 749 | } | 
|---|
| 750 |  | 
|---|
| 751 | void __init acpi_table_init_complete(void) | 
|---|
| 752 | { | 
|---|
| 753 | acpi_table_initrd_scan(); | 
|---|
| 754 | check_multiple_madt(); | 
|---|
| 755 | } | 
|---|
| 756 |  | 
|---|
| 757 | int __init acpi_table_init(void) | 
|---|
| 758 | { | 
|---|
| 759 | int ret; | 
|---|
| 760 |  | 
|---|
| 761 | ret = acpi_locate_initial_tables(); | 
|---|
| 762 | if (ret) | 
|---|
| 763 | return ret; | 
|---|
| 764 |  | 
|---|
| 765 | acpi_table_init_complete(); | 
|---|
| 766 |  | 
|---|
| 767 | return 0; | 
|---|
| 768 | } | 
|---|
| 769 |  | 
|---|
| 770 | static int __init acpi_parse_apic_instance(char *str) | 
|---|
| 771 | { | 
|---|
| 772 | if (!str) | 
|---|
| 773 | return -EINVAL; | 
|---|
| 774 |  | 
|---|
| 775 | if (kstrtoint(s: str, base: 0, res: &acpi_apic_instance)) | 
|---|
| 776 | return -EINVAL; | 
|---|
| 777 |  | 
|---|
| 778 | pr_notice( "Shall use APIC/MADT table %d\n", acpi_apic_instance); | 
|---|
| 779 |  | 
|---|
| 780 | return 0; | 
|---|
| 781 | } | 
|---|
| 782 | early_param( "acpi_apic_instance", acpi_parse_apic_instance); | 
|---|
| 783 |  | 
|---|
| 784 | static int __init acpi_force_table_verification_setup(char *s) | 
|---|
| 785 | { | 
|---|
| 786 | acpi_verify_table_checksum = true; | 
|---|
| 787 |  | 
|---|
| 788 | return 0; | 
|---|
| 789 | } | 
|---|
| 790 | early_param( "acpi_force_table_verification", acpi_force_table_verification_setup); | 
|---|
| 791 |  | 
|---|
| 792 | static int __init acpi_force_32bit_fadt_addr(char *s) | 
|---|
| 793 | { | 
|---|
| 794 | pr_info( "Forcing 32 Bit FADT addresses\n"); | 
|---|
| 795 | acpi_gbl_use32_bit_fadt_addresses = TRUE; | 
|---|
| 796 |  | 
|---|
| 797 | return 0; | 
|---|
| 798 | } | 
|---|
| 799 | early_param( "acpi_force_32bit_fadt_addr", acpi_force_32bit_fadt_addr); | 
|---|
| 800 |  | 
|---|