[tip:x86/apic] acpi: Provide mechanism to validate processors in the ACPI tables

From: tip-bot for Dou Liyang
Date: Thu Sep 22 2016 - 15:12:36 EST


Commit-ID: 8e089eaa1999def4bb954caa91941f29b0672b6a
Gitweb: http://git.kernel.org/tip/8e089eaa1999def4bb954caa91941f29b0672b6a
Author: Dou Liyang <douly.fnst@xxxxxxxxxxxxxx>
AuthorDate: Thu, 25 Aug 2016 16:35:19 +0800
Committer: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
CommitDate: Wed, 21 Sep 2016 21:18:39 +0200

acpi: Provide mechanism to validate processors in the ACPI tables

[Problem]

When we set cpuid <-> nodeid mapping to be persistent, it will use the DSDT
As we know, the ACPI tables are just like user's input in that respect, and
we don't crash if user's input is unreasonable.

Such as, the mapping of the proc_id and pxm in some machine's ACPI table is
like this:

proc_id | pxm
--------------------
0 <-> 0
1 <-> 0
2 <-> 1
3 <-> 1
89 <-> 0
89 <-> 0
89 <-> 0
89 <-> 1
89 <-> 1
89 <-> 2
89 <-> 3
.....

We can't be sure which one is correct to the proc_id 89. We may map a wrong
node to a cpu. When pages are allocated, this may cause a kernal panic.

So, we should provide mechanisms to validate the ACPI tables, just like we
do validation to check user's input in web project.

The mechanism is that the processor objects which have the duplicate IDs
are not valid.

[Solution]

We add a validation function, like this:

foreach Processor in DSDT
proc_id = get_ACPI_Processor_number(Processor)
if (proc_id exists )
mark both of them as being unreasonable;

The function will record the unique or duplicate processor IDs.

The duplicate processor IDs such as 89 are regarded as the unreasonable IDs
which mean that the processor objects in question are not valid.

[ tglx: Add __init[data] annotations ]

Signed-off-by: Dou Liyang <douly.fnst@xxxxxxxxxxxxxx>
Acked-by: Ingo Molnar <mingo@xxxxxxxxxx>
Cc: mika.j.penttila@xxxxxxxxx
Cc: len.brown@xxxxxxxxx
Cc: rafael@xxxxxxxxxx
Cc: rjw@xxxxxxxxxxxxx
Cc: yasu.isimatu@xxxxxxxxx
Cc: linux-mm@xxxxxxxxx
Cc: linux-acpi@xxxxxxxxxxxxxxx
Cc: isimatu.yasuaki@xxxxxxxxxxxxxx
Cc: gongzhaogang@xxxxxxxxxx
Cc: tj@xxxxxxxxxx
Cc: izumi.taku@xxxxxxxxxxxxxx
Cc: cl@xxxxxxxxx
Cc: chen.tang@xxxxxxxxxxxx
Cc: akpm@xxxxxxxxxxxxxxxxxxxx
Cc: kamezawa.hiroyu@xxxxxxxxxxxxxx
Cc: lenb@xxxxxxxxxx
Link: http://lkml.kernel.org/r/1472114120-3281-7-git-send-email-douly.fnst@xxxxxxxxxxxxxx
Signed-off-by: Thomas Gleixner <tglx@xxxxxxxxxxxxx>
---
drivers/acpi/acpi_processor.c | 79 +++++++++++++++++++++++++++++++++++++++++++
1 file changed, 79 insertions(+)

diff --git a/drivers/acpi/acpi_processor.c b/drivers/acpi/acpi_processor.c
index f9f23fd..f27c709 100644
--- a/drivers/acpi/acpi_processor.c
+++ b/drivers/acpi/acpi_processor.c
@@ -581,8 +581,87 @@ static struct acpi_scan_handler processor_container_handler = {
.attach = acpi_processor_container_attach,
};

+/* The number of the unique processor IDs */
+static int nr_unique_ids __initdata;
+
+/* The number of the duplicate processor IDs */
+static int nr_duplicate_ids __initdata;
+
+/* Used to store the unique processor IDs */
+static int unique_processor_ids[] __initdata = {
+ [0 ... NR_CPUS - 1] = -1,
+};
+
+/* Used to store the duplicate processor IDs */
+static int duplicate_processor_ids[] __initdata = {
+ [0 ... NR_CPUS - 1] = -1,
+};
+
+static void __init processor_validated_ids_update(int proc_id)
+{
+ int i;
+
+ if (nr_unique_ids == NR_CPUS||nr_duplicate_ids == NR_CPUS)
+ return;
+
+ /*
+ * Firstly, compare the proc_id with duplicate IDs, if the proc_id is
+ * already in the IDs, do nothing.
+ */
+ for (i = 0; i < nr_duplicate_ids; i++) {
+ if (duplicate_processor_ids[i] == proc_id)
+ return;
+ }
+
+ /*
+ * Secondly, compare the proc_id with unique IDs, if the proc_id is in
+ * the IDs, put it in the duplicate IDs.
+ */
+ for (i = 0; i < nr_unique_ids; i++) {
+ if (unique_processor_ids[i] == proc_id) {
+ duplicate_processor_ids[nr_duplicate_ids] = proc_id;
+ nr_duplicate_ids++;
+ return;
+ }
+ }
+
+ /*
+ * Lastly, the proc_id is a unique ID, put it in the unique IDs.
+ */
+ unique_processor_ids[nr_unique_ids] = proc_id;
+ nr_unique_ids++;
+}
+
+static acpi_status __init acpi_processor_ids_walk(acpi_handle handle,
+ u32 lvl,
+ void *context,
+ void **rv)
+{
+ acpi_status status;
+ union acpi_object object = { 0 };
+ struct acpi_buffer buffer = { sizeof(union acpi_object), &object };
+
+ status = acpi_evaluate_object(handle, NULL, NULL, &buffer);
+ if (ACPI_FAILURE(status))
+ acpi_handle_info(handle, "Not get the processor object\n");
+ else
+ processor_validated_ids_update(object.processor.proc_id);
+
+ return AE_OK;
+}
+
+static void __init acpi_processor_check_duplicates(void)
+{
+ /* Search all processor nodes in ACPI namespace */
+ acpi_walk_namespace(ACPI_TYPE_PROCESSOR, ACPI_ROOT_OBJECT,
+ ACPI_UINT32_MAX,
+ acpi_processor_ids_walk,
+ NULL, NULL, NULL);
+}
+
void __init acpi_processor_init(void)
{
+ acpi_processor_check_duplicates();
acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
acpi_scan_add_handler(&processor_container_handler);
}