From patchwork Tue Sep 29 23:45:42 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Al Stone X-Patchwork-Id: 54279 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-wi0-f198.google.com (mail-wi0-f198.google.com [209.85.212.198]) by patches.linaro.org (Postfix) with ESMTPS id 372AF23009 for ; Tue, 29 Sep 2015 23:46:06 +0000 (UTC) Received: by wicuu12 with SMTP id uu12sf13600209wic.2 for ; Tue, 29 Sep 2015 16:46:05 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:x-original-sender :x-original-authentication-results:precedence:mailing-list:list-id :list-post:list-help:list-archive:list-unsubscribe; bh=6PzecwVkgbFiTKXP3l6lIWBGL+xSiXAyJuinL9Er0k8=; b=LXbIeGkG7sKucDfeQUSUtwB1aNPv8c45uQvRVFExMkQl9xqPNeJHjKiYq0KjCinbvz Vu8rBAWVTXBLPyChLsACwPYBlMMNM1zBmtagdSYgtQ6KuPNIEtBFoLoZ+3tZaO74Rh6i 5bd+LgQ6Knqe1/4adpbok09rOtJorR6Lr8a9EANxUk2IqwRr15whCgtBSPem3k0cAJnz LiSYgybiaEnyYDkh5tAASP26f7UU3/LzN2w4N++tKTPZFZbSNXVOZNpyeG//YZpPcFod ovLkDgOcD0COh35OmdD1KBhwzZhPz/wJOd55gv0mA+etEkpUaAPH0eG5w9efVFd2JYp5 pZxA== X-Gm-Message-State: ALoCoQnp+iBwbcNXlqw6mzMORDyhmS5feREhLVfDAq5Fk3G7gj9nBkNHEUPrgYDaJxf5C6hOTd7J X-Received: by 10.180.210.212 with SMTP id mw20mr4291360wic.3.1443570365386; Tue, 29 Sep 2015 16:46:05 -0700 (PDT) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.25.141.198 with SMTP id p189ls8916lfd.79.gmail; Tue, 29 Sep 2015 16:46:05 -0700 (PDT) X-Received: by 10.112.52.168 with SMTP id u8mr197045lbo.48.1443570365017; Tue, 29 Sep 2015 16:46:05 -0700 (PDT) Received: from mail-la0-f50.google.com (mail-la0-f50.google.com. [209.85.215.50]) by mx.google.com with ESMTPS id c8si12117786laa.80.2015.09.29.16.46.04 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Sep 2015 16:46:04 -0700 (PDT) Received-SPF: pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) client-ip=209.85.215.50; Received: by lahh2 with SMTP id h2so27103262lah.0 for ; Tue, 29 Sep 2015 16:46:04 -0700 (PDT) X-Received: by 10.152.18.167 with SMTP id x7mr176423lad.29.1443570364511; Tue, 29 Sep 2015 16:46:04 -0700 (PDT) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patches@linaro.org Received: by 10.112.59.35 with SMTP id w3csp2426826lbq; Tue, 29 Sep 2015 16:46:01 -0700 (PDT) X-Received: by 10.107.14.4 with SMTP id 4mr1639876ioo.169.1443570361005; Tue, 29 Sep 2015 16:46:01 -0700 (PDT) Received: from mail-ig0-f181.google.com (mail-ig0-f181.google.com. [209.85.213.181]) by mx.google.com with ESMTPS id g79si19254494ioi.68.2015.09.29.16.46.00 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Sep 2015 16:46:00 -0700 (PDT) Received-SPF: pass (google.com: domain of al.stone@linaro.org designates 209.85.213.181 as permitted sender) client-ip=209.85.213.181; Received: by igbkq10 with SMTP id kq10so89325232igb.0 for ; Tue, 29 Sep 2015 16:46:00 -0700 (PDT) X-Received: by 10.50.62.46 with SMTP id v14mr25909763igr.79.1443570360098; Tue, 29 Sep 2015 16:46:00 -0700 (PDT) Received: from fidelio.ahs3.com (c-50-134-239-249.hsd1.co.comcast.net. [50.134.239.249]) by smtp.googlemail.com with ESMTPSA id r40sm12256182ioe.20.2015.09.29.16.45.58 (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 29 Sep 2015 16:45:58 -0700 (PDT) From: Al Stone To: linux-acpi@vger.kernel.org, linux-arm-kernel@lists.infradead.org Cc: linux-kernel@vger.kernel.org, linux-ia64@vger.kernel.org, linux-pm@vger.kernel.org, linaro-acpi@lists.linaro.org, linaro-kernel@lists.linaro.org, patches@linaro.org, Al Stone , "Rafael J. Wysocki" , Len Brown Subject: [PATCH v5 1/5] ACPI: add in a bad_madt_entry() function to eventually replace the macro Date: Tue, 29 Sep 2015 17:45:42 -0600 Message-Id: <1443570346-15378-2-git-send-email-al.stone@linaro.org> X-Mailer: git-send-email 2.4.3 In-Reply-To: <1443570346-15378-1-git-send-email-al.stone@linaro.org> References: <1443570346-15378-1-git-send-email-al.stone@linaro.org> X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: al.stone@linaro.org X-Original-Authentication-Results: mx.google.com; spf=pass (google.com: domain of patch+caf_=patchwork-forward=linaro.org@linaro.org designates 209.85.215.50 as permitted sender) smtp.mailfrom=patch+caf_=patchwork-forward=linaro.org@linaro.org Precedence: list Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org List-ID: X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , The existing BAD_MADT_ENTRY macro only checks that the size of the data structure for an MADT subtable matches the length entry in the subtable. This is, unfortunately, not reliable. Nor, as it turns out, does it have anything to do with what the length should be in any particular table. We introduce the bad_madt_entry() function that uses a data set to do some basic sanity checks on any given MADT subtable. Over time, as the spec changes, we should just be able to add entries to the data set to reflect the changes. What the data set captures is the allowed MADT subtable length for each type of subtable, for each revision of the specification. While there is a revision number in the MADT that we should be able to use to figure out the proper subtable length, it was not changed when subtables did. And, while there is a major and minor revision in the FADT that could also help, it was not always changed as the subtables changed either. So, the data set captures for each published version of the ACPI spec what the FADT revisions numbers should be, the corresponding MADT revision number, and the subtable types and lengths that were defined at that time. The sanity checks done are: -- is the length non-zero? -- is the subtable type defined/allowed for the revision of the FADT we're using? -- is the subtable type defined/allowed for the revision of the MADT we're using? -- is the length entry what it should be for this revision of the MADT and FADT? These checks are more thorough than the previous macro provided, and are now insulated from data structure size changes by ACPICA, which have been the source of other patches in the past. Now that the bad_madt_entry() function is available, we add code to also invoke it before any subtable handlers are called to use the info in the subtable. Subsequent patches will remove the use of the BAD_MADT_ENTRY macro which is now redundant as a result. Any ACPI functions that use acpi_parse_madt_entries() will always have all of the MADT subtables checked from now on. Signed-off-by: Al Stone Cc: Rafael J. Wysocki Cc: Len Brown --- drivers/acpi/tables.c | 247 +++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 246 insertions(+), 1 deletion(-) diff --git a/drivers/acpi/tables.c b/drivers/acpi/tables.c index 6c0f079..a2ed38a 100644 --- a/drivers/acpi/tables.c +++ b/drivers/acpi/tables.c @@ -210,6 +210,247 @@ void acpi_table_print_madt_entry(struct acpi_subtable_header *header) } } +/* + * The Long, Sad, True Story of the MADT + * or + * What does bad_madt_entry() actually do? + * + * Once upon a time in ACPI 1.0, there was the MADT. It was a nice table, + * and it had two subtables all of its own. But, it was also a pretty + * busy table, too, so over time the MADT gathered up other nice little + * subtables. By the time ACPI 6.0 came around, the MADT had 16 of the + * little guys. + * + * Now, the MADT kept a little counter around for the subtables. In fact, + * it kept two counters: one was the revision level, which was supposed to + * change when new subtables came to be, or as the ones already around grew + * up. The second counter was a type number, because the MADT needed a unique + * type for each subtable so he could tell them apart. But, sometimes the + * MADT got so busy, he forgot to increment the revision level when he needed + * to. Fortunately, the type counter kept increasing since that's the only + * way the MADT could find each little subtable. It just wouldn't do to have + * every subtable called Number 6. + * + * In the next valley over, a castle full of wizards was watching the MADT + * and made a pact to keep their own counter. Every time the MADT found a + * new subtable, or a subtable grew up, the wizards promised they would + * increment their counter. Well, wizards being the forgetful sort, they + * didn't alway do that. And, since there quite a lot of them, they + * couldn't always remember who was supposed to keep track of the MADT, + * especially if dinner was coming up soon. Their counter was called the + * spec version. + * + * Every now and then, the MADT would gather up all its little subtables + * and take them in to the cobbler to get new boots. This was a very, very + * meticulous cobbler, so every time they came, he wrote down all the boot + * sizes for all of the little subtables. The cobbler would ask each subtable + * for its length, check that against his careful notes, and then go get the + * right boots. Sometimes, a little subtable would change a bit, and their + * length did not match what the cobbler had written down. If the wizards + * or the MADT had incremented their counters, the cobbler would breath a + * sigh of relief and write down the new length as the right one. But, if + * none of the counters had changed, this would make the cobbler very, very + * mad. He couldn't tell if he had the right size boots or not for the + * little subtable. He would have to *guess* and this really bugged him. + * + * Well, when the cobbler got mad like this, he would go into hiding. He + * would not make or sell any boots. He would not go out at all. Pretty + * soon, the coffee shop would have to close because the cobbler wasn't + * coming by twice a day any more. Then the grocery store would have to + * close because he wouldn't eat much. After a while, everyone would panic + * and have to move from the village and go live with all their relatives + * (usually the ones they didn't like very much). + * + * Eventually, the cobbler would work his way out of his bad mood, and + * open up his boot business again. Then, everyone else could move back + * to the village and restart their lives, too. + * + * Fortunately, we have been able to collect up all the cobbler's careful + * notes (and we wrote them down below). We'll have to keep checking these + * notes over time, too, just as the cobbler does. But, in the meantime, + * we can avoid the panic and the reboot since we can make sure that each + * subtable is doing okay. And that's what bad_madt_entry() does. + * + * + * FADT Major Version -> 1 3 4 4 5 5 6 + * FADT Minor Version -> x x x x x 1 0 + * MADT revision -> 1 1 2 3 3 3 3 + * Spec Version -> 1.0 2.0 3.0b 4.0a 5.0b 5.1a 6.0 + * Subtable Name Type Expected Length -> + * Processor Local APIC 0x0 8 8 8 8 8 8 8 + * IO APIC 0x1 12 12 12 12 12 12 12 + * Int Src Override 0x2 10 10 10 10 10 10 10 + * NMI Src 0x3 8 8 8 8 8 8 8 + * Local APIC NMI Struct 0x4 6 6 6 6 6 6 6 + * Local APIC Addr Ovrrd 0x5 16 12 12 12 12 12 + * IO SAPIC 0x6 20 16 16 16 16 16 + * Local SAPIC 0x7 8 >16 >16 >16 >16 >16 + * Platform Int Src 0x8 16 16 16 16 16 16 + * Proc Local x2APIC 0x9 16 16 16 16 + * Local x2APIC NMI 0xa 12 12 12 12 + * GICC CPU I/F 0xb 40 76 80 + * GICD 0xc 24 24 24 + * GICv2m MSI 0xd 24 24 + * GICR 0xe 16 16 + * GIC ITS 0xf 16 + * + * In the table, each length entry is what should be in the length + * field of the subtable, and -- in general -- it should match the + * size of the struct for the subtable. Any value that is not set + * (i.e., is zero) indicates that the subtable is not defined for + * that version of the ACPI spec. + * + */ +#define SUBTABLE_UNDEFINED 0x00 +#define SUBTABLE_VARIABLE 0xff +#define NUM_SUBTABLE_TYPES 16 + +struct acpi_madt_subtable_lengths { + unsigned short major_version; /* from revision in FADT header */ + unsigned short minor_version; /* FADT field starting with 5.1 */ + unsigned short madt_version; /* MADT revision */ + unsigned short num_types; /* types possible for this version */ + unsigned short lengths[NUM_SUBTABLE_TYPES]; + /* subtable lengths, indexed by type */ +}; + +static struct acpi_madt_subtable_lengths spec_info[] = { + { /* for ACPI 1.0b */ + .major_version = 1, + .minor_version = 0, + .madt_version = 1, + .num_types = 5, + .lengths = { 8, 12, 10, 8, 6 } + }, + { /* for ACPI 2.0 */ + .major_version = 3, + .minor_version = 0, + .madt_version = 1, + .num_types = 9, + .lengths = { 8, 12, 10, 8, 6, 16, 20, 8, 16 } + }, + { /* for ACPI 3.0b */ + .major_version = 4, + .minor_version = 0, + .madt_version = 2, + .num_types = 9, + .lengths = { 8, 12, 10, 8, 6, 12, 16, SUBTABLE_VARIABLE, 16 } + }, + { /* for ACPI 4.0a */ + .major_version = 4, + .minor_version = 0, + .madt_version = 3, + .num_types = 11, + .lengths = { 8, 12, 10, 8, 6, 12, 16, SUBTABLE_VARIABLE, + 16, 16, 12 } + }, + { /* for ACPI 5.0b */ + .major_version = 5, + .minor_version = 0, + .madt_version = 3, + .num_types = 13, + .lengths = { 8, 12, 10, 8, 6, 12, 16, SUBTABLE_VARIABLE, + 16, 16, 12, 40, 24 } + }, + { /* for ACPI 5.1a */ + .major_version = 5, + .minor_version = 1, + .madt_version = 3, + .num_types = 15, + .lengths = { 8, 12, 10, 8, 6, 12, 16, SUBTABLE_VARIABLE, + 16, 16, 12, 76, 24, 24, 16 } + }, + { /* for ACPI 6.0 */ + .major_version = 6, + .minor_version = 0, + .madt_version = 3, + .num_types = 16, + .lengths = { 8, 12, 10, 8, 6, 12, 16, SUBTABLE_VARIABLE, + 16, 16, 12, 80, 24, 24, 16, 16 } + }, + { /* terminator */ + .major_version = 0, + .minor_version = 0, + .madt_version = 0, + .num_types = 0, + .lengths = { 0 } + } +}; + +static int __init bad_madt_entry(struct acpi_table_header *table, + struct acpi_subtable_header *entry) +{ + struct acpi_madt_subtable_lengths *ms; + struct acpi_table_madt *madt; + unsigned short major; + unsigned short minor; + unsigned short len; + + /* simple sanity checking on MADT subtable entries */ + if (!entry || !table) + return 1; + + /* FADT minor numbers were not introduced until ACPI 5.1 */ + major = acpi_gbl_FADT.header.revision; + if (major >= 5 && acpi_gbl_FADT.header.length >= 268) + minor = acpi_gbl_FADT.minor_revision; + else + minor = 0; + + madt = (struct acpi_table_madt *)table; + ms = spec_info; + while (ms->num_types != 0) { + if (ms->major_version == major && + ms->minor_version == minor && + ms->madt_version == madt->header.revision) + break; + ms++; + } + if (!ms->num_types) { + pr_err("undefined version for either FADT %d.%d or MADT %d\n", + major, minor, madt->header.revision); + return 1; + } + + if (entry->type >= ms->num_types) { + pr_err("undefined MADT subtable type for FADT %d.%d: %d (length %d)\n", + major, minor, entry->type, entry->length); + return 1; + } + + /* verify that the table is allowed for this version of the spec */ + len = ms->lengths[entry->type]; + if (!len) { + pr_err("MADT subtable %d not defined for FADT %d.%d\n", + entry->type, major, minor); + return 1; + } + + /* verify that the length is what we expect */ + if (len == SUBTABLE_VARIABLE) { + if (entry->type == ACPI_MADT_TYPE_LOCAL_SAPIC) { + struct acpi_madt_local_sapic *lsapic = + (struct acpi_madt_local_sapic *)entry; + int proper_len = sizeof(struct acpi_madt_local_sapic) + + strlen(lsapic->uid_string) + 1; + + if (proper_len != entry->length) { + pr_err("Variable length MADT subtable %d is wrong length: %d, should be: %d\n", + entry->type, entry->length, proper_len); + return 1; + } + } + } else { + if (entry->length != len) { + pr_err("MADT subtable %d is wrong length: %d, should be: %d\n", + entry->type, entry->length, len); + return 1; + } + } + + return 0; +} + /** * acpi_parse_entries_array - for each proc_num find a suitable subtable * @@ -265,6 +506,10 @@ acpi_parse_entries_array(char *id, unsigned long table_size, if (max_entries && count >= max_entries) break; + if (!strncmp(id, ACPI_SIG_MADT, 4) && + bad_madt_entry(table_header, entry)) + return -EINVAL; + for (i = 0; i < proc_num; i++) { if (entry->type != proc[i].id) continue; @@ -407,7 +652,7 @@ int __init acpi_table_parse(char *id, acpi_tbl_table_handler handler) return -ENODEV; } -/* +/* * The BIOS is supposed to supply a single APIC/MADT, * but some report two. Provide a knob to use either. * (don't you wish instance 0 and 1 were not the same?)