|
4 | 4 | #include "error.h"
|
5 | 5 | #include "../string.h"
|
6 | 6 |
|
| 7 | +#include <linux/numa.h> |
7 | 8 | #include <linux/efi.h>
|
8 | 9 | #include <asm/efi.h>
|
9 | 10 |
|
| 11 | +/* |
| 12 | + * Longest parameter of 'acpi=' is 'copy_dsdt', plus an extra '\0' |
| 13 | + * for termination. |
| 14 | + */ |
| 15 | +#define MAX_ACPI_ARG_LENGTH 10 |
| 16 | + |
| 17 | +/* |
| 18 | + * Immovable memory regions representation. Max amount of memory regions is |
| 19 | + * MAX_NUMNODES*2. |
| 20 | + */ |
| 21 | +struct mem_vector immovable_mem[MAX_NUMNODES*2]; |
| 22 | + |
10 | 23 | /*
|
11 | 24 | * Max length of 64-bit hex address string is 19, prefix "0x" + 16 hex
|
12 | 25 | * digits, and '\0' for termination.
|
@@ -203,3 +216,111 @@ acpi_physical_address get_rsdp_addr(void)
|
203 | 216 |
|
204 | 217 | return pa;
|
205 | 218 | }
|
| 219 | + |
| 220 | +#if defined(CONFIG_RANDOMIZE_BASE) && defined(CONFIG_MEMORY_HOTREMOVE) |
| 221 | +/* Compute SRAT address from RSDP. */ |
| 222 | +static unsigned long get_acpi_srat_table(void) |
| 223 | +{ |
| 224 | + unsigned long root_table, acpi_table; |
| 225 | + struct acpi_table_header *header; |
| 226 | + struct acpi_table_rsdp *rsdp; |
| 227 | + u32 num_entries, size, len; |
| 228 | + char arg[10]; |
| 229 | + u8 *entry; |
| 230 | + |
| 231 | + rsdp = (struct acpi_table_rsdp *)(long)boot_params->acpi_rsdp_addr; |
| 232 | + if (!rsdp) |
| 233 | + return 0; |
| 234 | + |
| 235 | + /* Get ACPI root table from RSDP.*/ |
| 236 | + if (!(cmdline_find_option("acpi", arg, sizeof(arg)) == 4 && |
| 237 | + !strncmp(arg, "rsdt", 4)) && |
| 238 | + rsdp->xsdt_physical_address && |
| 239 | + rsdp->revision > 1) { |
| 240 | + root_table = rsdp->xsdt_physical_address; |
| 241 | + size = ACPI_XSDT_ENTRY_SIZE; |
| 242 | + } else { |
| 243 | + root_table = rsdp->rsdt_physical_address; |
| 244 | + size = ACPI_RSDT_ENTRY_SIZE; |
| 245 | + } |
| 246 | + |
| 247 | + if (!root_table) |
| 248 | + return 0; |
| 249 | + |
| 250 | + header = (struct acpi_table_header *)root_table; |
| 251 | + len = header->length; |
| 252 | + if (len < sizeof(struct acpi_table_header) + size) |
| 253 | + return 0; |
| 254 | + |
| 255 | + num_entries = (len - sizeof(struct acpi_table_header)) / size; |
| 256 | + entry = (u8 *)(root_table + sizeof(struct acpi_table_header)); |
| 257 | + |
| 258 | + while (num_entries--) { |
| 259 | + if (size == ACPI_RSDT_ENTRY_SIZE) |
| 260 | + acpi_table = *(u32 *)entry; |
| 261 | + else |
| 262 | + acpi_table = *(u64 *)entry; |
| 263 | + |
| 264 | + if (acpi_table) { |
| 265 | + header = (struct acpi_table_header *)acpi_table; |
| 266 | + |
| 267 | + if (ACPI_COMPARE_NAME(header->signature, ACPI_SIG_SRAT)) |
| 268 | + return acpi_table; |
| 269 | + } |
| 270 | + entry += size; |
| 271 | + } |
| 272 | + return 0; |
| 273 | +} |
| 274 | + |
| 275 | +/** |
| 276 | + * count_immovable_mem_regions - Parse SRAT and cache the immovable |
| 277 | + * memory regions into the immovable_mem array. |
| 278 | + * |
| 279 | + * Return the number of immovable memory regions on success, 0 on failure: |
| 280 | + * |
| 281 | + * - Too many immovable memory regions |
| 282 | + * - ACPI off or no SRAT found |
| 283 | + * - No immovable memory region found. |
| 284 | + */ |
| 285 | +int count_immovable_mem_regions(void) |
| 286 | +{ |
| 287 | + unsigned long table_addr, table_end, table; |
| 288 | + struct acpi_subtable_header *sub_table; |
| 289 | + struct acpi_table_header *table_header; |
| 290 | + char arg[MAX_ACPI_ARG_LENGTH]; |
| 291 | + int num = 0; |
| 292 | + |
| 293 | + if (cmdline_find_option("acpi", arg, sizeof(arg)) == 3 && |
| 294 | + !strncmp(arg, "off", 3)) |
| 295 | + return 0; |
| 296 | + |
| 297 | + table_addr = get_acpi_srat_table(); |
| 298 | + if (!table_addr) |
| 299 | + return 0; |
| 300 | + |
| 301 | + table_header = (struct acpi_table_header *)table_addr; |
| 302 | + table_end = table_addr + table_header->length; |
| 303 | + table = table_addr + sizeof(struct acpi_table_srat); |
| 304 | + |
| 305 | + while (table + sizeof(struct acpi_subtable_header) < table_end) { |
| 306 | + sub_table = (struct acpi_subtable_header *)table; |
| 307 | + if (sub_table->type == ACPI_SRAT_TYPE_MEMORY_AFFINITY) { |
| 308 | + struct acpi_srat_mem_affinity *ma; |
| 309 | + |
| 310 | + ma = (struct acpi_srat_mem_affinity *)sub_table; |
| 311 | + if (!(ma->flags & ACPI_SRAT_MEM_HOT_PLUGGABLE) && ma->length) { |
| 312 | + immovable_mem[num].start = ma->base_address; |
| 313 | + immovable_mem[num].size = ma->length; |
| 314 | + num++; |
| 315 | + } |
| 316 | + |
| 317 | + if (num >= MAX_NUMNODES*2) { |
| 318 | + debug_putstr("Too many immovable memory regions, aborting.\n"); |
| 319 | + return 0; |
| 320 | + } |
| 321 | + } |
| 322 | + table += sub_table->length; |
| 323 | + } |
| 324 | + return num; |
| 325 | +} |
| 326 | +#endif /* CONFIG_RANDOMIZE_BASE && CONFIG_MEMORY_HOTREMOVE */ |
0 commit comments