diff mbox

[RFC,02/10] acpi: install SSDT tables from initrd

Message ID 1459417026-6697-3-git-send-email-octavian.purdila@intel.com (mailing list archive)
State New, archived
Headers show

Commit Message

Octavian Purdila March 31, 2016, 9:36 a.m. UTC
This patch allows loading user defined SSDTs from the first,
uncompressed, initrd. The SSDT aml code must be stored in files under
the /kernel/firmware/acpi/overlay path.

Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
---
 Documentation/acpi/ssdt-overlays.txt | 94 ++++++++++++++++++++++++++++++++++++
 drivers/acpi/bus.c                   | 63 ++++++++++++++++++++++++
 2 files changed, 157 insertions(+)
 create mode 100644 Documentation/acpi/ssdt-overlays.txt

Comments

Lv Zheng April 1, 2016, 5:05 a.m. UTC | #1
Hi,

IMO, there is already a similar function upstreamed:
https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85cc81
Could it work for your use case?

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-
> owner@vger.kernel.org] On Behalf Of Octavian Purdila
> Subject: [RFC PATCH 02/10] acpi: install SSDT tables from initrd
> 
> This patch allows loading user defined SSDTs from the first,
> uncompressed, initrd. The SSDT aml code must be stored in files under
> the /kernel/firmware/acpi/overlay path.
> 
> Signed-off-by: Octavian Purdila <octavian.purdila@intel.com>
> ---
>  Documentation/acpi/ssdt-overlays.txt | 94
> ++++++++++++++++++++++++++++++++++++
>  drivers/acpi/bus.c                   | 63 ++++++++++++++++++++++++
>  2 files changed, 157 insertions(+)
>  create mode 100644 Documentation/acpi/ssdt-overlays.txt
> 
> diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-
> overlays.txt
> new file mode 100644
> index 0000000..a94c3f9
> --- /dev/null
> +++ b/Documentation/acpi/ssdt-overlays.txt
> @@ -0,0 +1,94 @@
> +
> +In order to support ACPI open-ended hardware configurations (e.g.
> development
> +boards) we need a way to augment the ACPI configuration provided by the
> firmware
> +image. A common example is connecting sensors on I2C / SPI buses on
> development
> +boards.
> +
> +Although this can be accomplished by creating a kernel platform driver or
> +recompiling the firmware image with updated ACPI tables, neither is practical:
> +the former proliferates board specific kernel code while the latter requires
> +access to firmware tools which are often not publicly available.
> +
> +Because ACPI supports external references in AML code a more practical
> +way to augment firmware ACPI configuration is by dynamically loading
> +user defined SSDT tables that contain the board specific information.
> +
> +For example, to enumerate a Bosch BMA222E accelerometer on the I2C bus
> of the
> +Minnowboard MAX development board exposed via the LSE connector [1],
> the
> +following ASL code can be used:
> +
> +DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003)
> +{
> +    External (\_SB.I2C6, DeviceObj)
> +
> +    Scope (\_SB.I2C6)
> +    {
> +        Device (STAC)
> +        {
> +            Name (_ADR, Zero)
> +            Name (_HID, "BMA222E")
> +
> +            Method (_CRS, 0, Serialized)
> +            {
> +                Name (RBUF, ResourceTemplate ()
> +                {
> +                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
> +                                  AddressingMode7Bit, "\\_SB.I2C6", 0x00,
> +                                  ResourceConsumer, ,)
> +                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
> +                             "\\_SB.GPO2", 0x00, ResourceConsumer, , )
> +                    { // Pin list
> +                        0
> +                    }
> +                })
> +                Return (RBUF)
> +            }
> +        }
> +    }
> +}
> +
> +which can then be compiled to AML binary format:
> +
> +$ iasl minnowmax.asl
> +
> +Intel ACPI Component Architecture
> +ASL Optimizing Compiler version 20140214-64 [Mar 29 2014]
> +Copyright (c) 2000 - 2014 Intel Corporation
> +
> +ASL Input:     minnomax.asl - 30 lines, 614 bytes, 7 keywords
> +AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable
> opcodes
> +
> +[1]
> http://wiki.minnowboard.org/MinnowBoard_MAX#Low_Speed_Expansion_Co
> nnector_.28Top.29
> +
> +The resulting AML code can then be loaded by the kernel using one of the
> methods
> +below.
> +
> +== Loading ACPI SSDTs from initrd ==
> +
> +This option allows loading of user defined SSDTs from initrd and it is useful
> +when the system does not support EFI or when there is not enough EFI
> storage.
> +
> +It works in a similar way with initrd based ACPI tables overrides: SSDT aml
> code
> +must be placed in the first, uncompressed, initrd under the
> +"kernel/firmware/acpi/overlay" path. We use a different path than the initrd
> +tables override to avoid conflicts with the override feature.
> +
> +Multiple files can be used and this will translate in loading multiple
> +tables. Only tables with the SSDT signature will be loaded.
> +
> +Here is an example:
> +
> +# Add the raw ACPI tables to an uncompressed cpio archive.
> +# They must be put into a /kernel/firmware/acpi/overlay directory inside the
> +# cpio archive.
> +# The uncompressed cpio archive must be the first.
> +# Other, typically compressed cpio archives, must be
> +# concatenated on top of the uncompressed one.
> +mkdir -p kernel/firmware/acpi
> +cp ssdt.aml kernel/firmware/acpi
> +
> +# Create the uncompressed cpio archive and concatenate the original initrd
> +# on top:
> +find kernel | cpio -H newc --create > /boot/instrumented_initrd
> +cat /boot/initrd >>/boot/instrumented_initrd
> +
> diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
> index 891c42d..5e0d076 100644
> --- a/drivers/acpi/bus.c
> +++ b/drivers/acpi/bus.c
> @@ -37,9 +37,14 @@
>  #include <acpi/apei.h>
>  #include <linux/dmi.h>
>  #include <linux/suspend.h>
> +#include <linux/initrd.h>
> +#include <linux/earlycpio.h>
> 
>  #include "internal.h"
> 
> +#undef pr_fmt
> +#define pr_fmt(fmt) "ACPI: " fmt
> +
>  #define _COMPONENT		ACPI_BUS_COMPONENT
>  ACPI_MODULE_NAME("bus");
> 
> @@ -863,6 +868,62 @@ static int __init acpi_bus_init_irq(void)
>  	return 0;
>  }
> 
> +void __init acpi_load_initrd_ssdts(void)
> +{
> +	void *data = (void *)initrd_start;
> +	int size = initrd_end - initrd_start;
> +	const char *path = "kernel/firmware/acpi/overlay";
> +	long offset = 0;
> +	struct cpio_data file;
> +	struct acpi_table_header *header;
> +	void *table;
> +	acpi_status status;
> +
> +	while (true) {
> +		file = find_cpio_data(path, data, size, &offset);
> +		if (!file.data)
> +			break;
> +
> +		data += offset;
> +		size -= offset;
> +
> +		if (file.size < sizeof(struct acpi_table_header)) {
> +			pr_err("initrd table smaller than ACPI header
> [%s%s]\n",
> +			       path, file.name);
> +			continue;
> +		}
> +
> +		header = file.data;
> +
> +		if (file.size != header->length) {
> +			pr_err("initrd file / table length mismatch [%s%s]\n",
> +			       path, file.name);
> +			continue;
> +		}
> +
> +		if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
> +			pr_warn("skipping non-SSDT initrd table [%s%s]\n",
> +				path, file.name);
> +			continue;
> +		}
> +
> +		table = kmemdup(file.data, file.size, GFP_KERNEL);
> +		if (!table)
> +			continue;
> +
> +		status = acpi_install_table((uintptr_t)table, 0);
> +		if (ACPI_FAILURE(status)) {
> +			pr_err("failed to install SSDT from initrd [%s%s]\n",
> +			       path, file.name);
> +			kfree(table);
> +		}
> +
> +		pr_info("installed SSDT table found in initrd [%s%s][0x%x]\n",
> +			path, file.name, header->length);
> +		add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
> +	}
> +}
> +
[Lv Zheng] 
I can see that this is so similar to the acpi_initrd_initialize_tables() which is in the drivers/acpi/osl.c.
Please check.

Thanks and best regards
-Lv

>  /**
>   * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
>   *
> @@ -911,6 +972,8 @@ void __init acpi_early_init(void)
>  		goto error0;
>  	}
> 
> +	acpi_load_initrd_ssdts();
> +
>  	status = acpi_load_tables();
>  	if (ACPI_FAILURE(status)) {
>  		printk(KERN_ERR PREFIX
> --
> 1.9.1
> 
> --
> To unsubscribe from this list: send the line "unsubscribe linux-acpi" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Octavian Purdila April 1, 2016, 10:11 a.m. UTC | #2
On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:
> Hi,
>
> IMO, there is already a similar function upstreamed:
> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85cc81
> Could it work for your use case?

Yes, it is basically the same.

The only difference is on how we handle taint. I think we should use a
new taint for overlays and that we don't need to disable lockdep.

BTW, why is lockdep disabled when we override?
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Octavian Purdila April 4, 2016, 1:07 p.m. UTC | #3
On Fri, Apr 1, 2016 at 1:11 PM, Octavian Purdila
<octavian.purdila@intel.com> wrote:
> On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:
>> Hi,
>>
>> IMO, there is already a similar function upstreamed:
>> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85cc81
>> Could it work for your use case?
>
> Yes, it is basically the same.
>
> The only difference is on how we handle taint. I think we should use a
> new taint for overlays and that we don't need to disable lockdep.
>
> BTW, why is lockdep disabled when we override?

The other thing I forgot to mention is that I think we should allow
installing new tables even if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not
selected. IMO the override and overlay functionality is different,
with the latter being more then a debug option.

I will prepare a patch for the next version of the series to decouple
installing new tables from CONFIG_ACPI_INITRD_TABLE_OVERRIDE.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lv Zheng April 5, 2016, 12:49 a.m. UTC | #4
Hi,

> From: Octavian Purdila [mailto:octavian.purdila@intel.com]

> Subject: Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd

> 

> On Fri, Apr 1, 2016 at 1:11 PM, Octavian Purdila

> <octavian.purdila@intel.com> wrote:

> > On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:

> >> Hi,

> >>

> >> IMO, there is already a similar function upstreamed:

> >>

> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85c

> c81

> >> Could it work for your use case?

> >

> > Yes, it is basically the same.

> >

> > The only difference is on how we handle taint. I think we should use a

> > new taint for overlays and that we don't need to disable lockdep.

> >

> > BTW, why is lockdep disabled when we override?

> 

> The other thing I forgot to mention is that I think we should allow

> installing new tables even if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not

> selected. IMO the override and overlay functionality is different,

> with the latter being more then a debug option.

[Lv Zheng] 
I don't think so. The initrd override mechanism is not dependent on CONFIG_ACPI_DEBUG.
According to the spec, we can allow a higher versioning same table (same table sig, table id, table oem id) to override the old tables as a patching functionality.
So both the functionalities are not debug options and serve for the same purpose from this point of view.
And IMO that's why the initrd override mechanism needn't be dependent on CONFIG_ACPI_DEBUG.

I'm really OK with removing the acpi_table_taint() for CONFIG_ACPI_INITRD_TABLE_OVERRIDE but leaving some info messages indicating the table upgrades.
I don't think this mechanism is unsafe.
It happens during a initialization step occurring before the table is loaded and hence should be safe even the synchronization is not so robust in ACPICA.
And with the revision support added, we should be able to allow vendors to update the buggy tables.
That means the tables may be originated from the safe sources - the vendors.

> 

> I will prepare a patch for the next version of the series to decouple

> installing new tables from CONFIG_ACPI_INITRD_TABLE_OVERRIDE.

[Lv Zheng] 
I don't think they need to be decoupled.
The use case is:
If there is an ACPI table in initrd image and:
1. if the table's revision is higher than the existing one, override the existing one;
2. if the table is a brand new one, install it.

Thanks and best regards
-Lv
Lv Zheng April 5, 2016, 12:57 a.m. UTC | #5
SGksDQoNCj4gRnJvbTogbGludXgtYWNwaS1vd25lckB2Z2VyLmtlcm5lbC5vcmcgW21haWx0bzps
aW51eC1hY3BpLQ0KPiBvd25lckB2Z2VyLmtlcm5lbC5vcmddIE9uIEJlaGFsZiBPZiBPY3Rhdmlh
biBQdXJkaWxhDQo+IFN1YmplY3Q6IFJlOiBbUkZDIFBBVENIIDAyLzEwXSBhY3BpOiBpbnN0YWxs
IFNTRFQgdGFibGVzIGZyb20gaW5pdHJkDQo+IA0KPiBPbiBGcmksIEFwciAxLCAyMDE2IGF0IDg6
MDUgQU0sIFpoZW5nLCBMdiA8bHYuemhlbmdAaW50ZWwuY29tPiB3cm90ZToNCj4gPiBIaSwNCj4g
Pg0KPiA+IElNTywgdGhlcmUgaXMgYWxyZWFkeSBhIHNpbWlsYXIgZnVuY3Rpb24gdXBzdHJlYW1l
ZDoNCj4gPg0KPiBodHRwczovL2dpdC5rZXJuZWwub3JnL2NnaXQvbGludXgva2VybmVsL2dpdC90
b3J2YWxkcy9saW51eC5naXQvY29tbWl0Lz9pZD1jODVjDQo+IGM4MQ0KPiA+IENvdWxkIGl0IHdv
cmsgZm9yIHlvdXIgdXNlIGNhc2U/DQo+IA0KPiBZZXMsIGl0IGlzIGJhc2ljYWxseSB0aGUgc2Ft
ZS4NCj4gDQo+IFRoZSBvbmx5IGRpZmZlcmVuY2UgaXMgb24gaG93IHdlIGhhbmRsZSB0YWludC4g
SSB0aGluayB3ZSBzaG91bGQgdXNlIGENCj4gbmV3IHRhaW50IGZvciBvdmVybGF5cyBhbmQgdGhh
dCB3ZSBkb24ndCBuZWVkIHRvIGRpc2FibGUgbG9ja2RlcC4NCj4gDQo+IEJUVywgd2h5IGlzIGxv
Y2tkZXAgZGlzYWJsZWQgd2hlbiB3ZSBvdmVycmlkZT8NCltMdiBaaGVuZ10gDQpJIGd1ZXNzIHRo
aXMgaXMgYmVjYXVzZSBvZiB0aGUgb2xkIHN5bmNocm9uaXphdGlvbiBidWdzLg0KT3JpZ2luYWxs
eSwgdGhlIHRhYmxlIGhhbmRsZXIgbWF5IHJlY2VpdmUgdGFibGUgZXZlbnRzIHdoZW4gdGhlIHRh
YmxlIGlzIGluc3RhbGxlZC4NCkFuZCB0aGF0IG1heSB0cmlnZ2VyIGxvY2sgaXNzdWVzIGluIHN1
Y2ggYW4gZWFybHkgc3RhZ2UuDQoNCkkgZG9uJ3QgdGhpbmsgdGhlIGFjcGlfdGFibGVfdGFpbnQo
KSBuZWVkIHRvIGJlIHRoZXJlIG5vdy4NClRoZSBvdmVycmlkZSBtZWNoYW5pc21zIG5vdyBoYXBw
ZW4gaW4gYW4gaW5pdGlhbGl6YXRpb24gc3RlcCBiZWZvcmUgdGhlIHRhYmxlcyBhcmUgbG9hZGVk
Lg0KSXQgc2hvdWxkIGJlIHNhZmUgZXZlbiB0aGUgc3luY2hyb25pemF0aW9uIGlzIG5vdCBzbyBy
b2J1c3QgaW4gQUNQSUNBLg0KQmVjYXVzZSBkdXJpbmcgdGhpcyBzdGVwLCBhbGwgdGhpbmdzIGFy
ZSBzZXJpYWwuDQpJTU8sIHlvdSBjYW4gcmVtb3ZlIGFjcGlfdGFibGVfdGFpbnQoKS4NCg0KVGhh
bmtzIGFuZCBiZXN0IHJlZ2FyZHMNCi1Mdg0KDQoNCj4gLS0NCj4gVG8gdW5zdWJzY3JpYmUgZnJv
bSB0aGlzIGxpc3Q6IHNlbmQgdGhlIGxpbmUgInVuc3Vic2NyaWJlIGxpbnV4LWFjcGkiIGluDQo+
IHRoZSBib2R5IG9mIGEgbWVzc2FnZSB0byBtYWpvcmRvbW9Admdlci5rZXJuZWwub3JnDQo+IE1v
cmUgbWFqb3Jkb21vIGluZm8gYXQgIGh0dHA6Ly92Z2VyLmtlcm5lbC5vcmcvbWFqb3Jkb21vLWlu
Zm8uaHRtbA0K
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Octavian Purdila April 5, 2016, 7:23 a.m. UTC | #6
On Tue, Apr 5, 2016 at 3:49 AM, Zheng, Lv <lv.zheng@intel.com> wrote:
> Hi,
>
>> From: Octavian Purdila [mailto:octavian.purdila@intel.com]
>> Subject: Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd
>>
>> On Fri, Apr 1, 2016 at 1:11 PM, Octavian Purdila
>> <octavian.purdila@intel.com> wrote:
>> > On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:
>> >> Hi,
>> >>
>> >> IMO, there is already a similar function upstreamed:
>> >>
>> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85c
>> c81
>> >> Could it work for your use case?
>> >
>> > Yes, it is basically the same.
>> >
>> > The only difference is on how we handle taint. I think we should use a
>> > new taint for overlays and that we don't need to disable lockdep.
>> >
>> > BTW, why is lockdep disabled when we override?
>>
>> The other thing I forgot to mention is that I think we should allow
>> installing new tables even if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not
>> selected. IMO the override and overlay functionality is different,
>> with the latter being more then a debug option.
> [Lv Zheng]
> I don't think so. The initrd override mechanism is not dependent on CONFIG_ACPI_DEBUG.
> According to the spec, we can allow a higher versioning same table (same table sig, table id, table oem id) to override the old tables as a patching functionality.
> So both the functionalities are not debug options and serve for the same purpose from this point of view.
> And IMO that's why the initrd override mechanism needn't be dependent on CONFIG_ACPI_DEBUG.
>

The problem is that CONFIG_ACPI_INITRD_TABLE_OVERRIDE is presented as
a debug option in Documentation/initrd_table_override.txt and most
distributions are not selecting it which makes it hard to use it in
practice.

> I'm really OK with removing the acpi_table_taint() for CONFIG_ACPI_INITRD_TABLE_OVERRIDE but leaving some info messages indicating the table upgrades.
> I don't think this mechanism is unsafe.
> It happens during a initialization step occurring before the table is loaded and hence should be safe even the synchronization is not so robust in ACPICA.
> And with the revision support added, we should be able to allow vendors to update the buggy tables.
> That means the tables may be originated from the safe sources - the vendors.
>
>>
>> I will prepare a patch for the next version of the series to decouple
>> installing new tables from CONFIG_ACPI_INITRD_TABLE_OVERRIDE.
> [Lv Zheng]
> I don't think they need to be decoupled.
> The use case is:
> If there is an ACPI table in initrd image and:
> 1. if the table's revision is higher than the existing one, override the existing one;
> 2. if the table is a brand new one, install it.
>

The implementation will stay the same of course, I was just suggesting
to move CONFIG_ACPI_INITRD_TABLE_OVERRIDE in
acpi_os_physical_table_override to allow new tables to be loaded even
if the option is not selected.
--
To unsubscribe from this list: send the line "unsubscribe linux-spi" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Lv Zheng April 6, 2016, 6:15 a.m. UTC | #7
Hi,

> From: linux-acpi-owner@vger.kernel.org [mailto:linux-acpi-

> owner@vger.kernel.org] On Behalf Of Octavian Purdila

> Subject: Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd

> 

> On Tue, Apr 5, 2016 at 3:49 AM, Zheng, Lv <lv.zheng@intel.com> wrote:

> > Hi,

> >

> >> From: Octavian Purdila [mailto:octavian.purdila@intel.com]

> >> Subject: Re: [RFC PATCH 02/10] acpi: install SSDT tables from initrd

> >>

> >> On Fri, Apr 1, 2016 at 1:11 PM, Octavian Purdila

> >> <octavian.purdila@intel.com> wrote:

> >> > On Fri, Apr 1, 2016 at 8:05 AM, Zheng, Lv <lv.zheng@intel.com> wrote:

> >> >> Hi,

> >> >>

> >> >> IMO, there is already a similar function upstreamed:

> >> >>

> >>

> https://git.kernel.org/cgit/linux/kernel/git/torvalds/linux.git/commit/?id=c85c

> >> c81

> >> >> Could it work for your use case?

> >> >

> >> > Yes, it is basically the same.

> >> >

> >> > The only difference is on how we handle taint. I think we should use a

> >> > new taint for overlays and that we don't need to disable lockdep.

> >> >

> >> > BTW, why is lockdep disabled when we override?

> >>

> >> The other thing I forgot to mention is that I think we should allow

> >> installing new tables even if CONFIG_ACPI_INITRD_TABLE_OVERRIDE is not

> >> selected. IMO the override and overlay functionality is different,

> >> with the latter being more then a debug option.

> > [Lv Zheng]

> > I don't think so. The initrd override mechanism is not dependent on

> CONFIG_ACPI_DEBUG.

> > According to the spec, we can allow a higher versioning same table (same

> table sig, table id, table oem id) to override the old tables as a patching

> functionality.

> > So both the functionalities are not debug options and serve for the same

> purpose from this point of view.

> > And IMO that's why the initrd override mechanism needn't be dependent on

> CONFIG_ACPI_DEBUG.

> >

> 

> The problem is that CONFIG_ACPI_INITRD_TABLE_OVERRIDE is presented as

> a debug option in Documentation/initrd_table_override.txt and most

> distributions are not selecting it which makes it hard to use it in

> practice.

> 

> > I'm really OK with removing the acpi_table_taint() for

> CONFIG_ACPI_INITRD_TABLE_OVERRIDE but leaving some info messages

> indicating the table upgrades.

> > I don't think this mechanism is unsafe.

> > It happens during a initialization step occurring before the table is loaded and

> hence should be safe even the synchronization is not so robust in ACPICA.

> > And with the revision support added, we should be able to allow vendors to

> update the buggy tables.

> > That means the tables may be originated from the safe sources - the vendors.

> >

> >>

> >> I will prepare a patch for the next version of the series to decouple

> >> installing new tables from CONFIG_ACPI_INITRD_TABLE_OVERRIDE.

> > [Lv Zheng]

> > I don't think they need to be decoupled.

> > The use case is:

> > If there is an ACPI table in initrd image and:

> > 1. if the table's revision is higher than the existing one, override the existing

> one;

> > 2. if the table is a brand new one, install it.

> >

> 

> The implementation will stay the same of course, I was just suggesting

> to move CONFIG_ACPI_INITRD_TABLE_OVERRIDE in

> acpi_os_physical_table_override to allow new tables to be loaded even

> if the option is not selected.

[Lv Zheng] 
This sounds reasonable.
Or you can rename it to CONFIG_ACPI_TABLE_UPGRADE and make it default 'y'.
Also you need to remove acpi_table_taint() which is not so useful now.

Thanks and best regards
-Lv
diff mbox

Patch

diff --git a/Documentation/acpi/ssdt-overlays.txt b/Documentation/acpi/ssdt-overlays.txt
new file mode 100644
index 0000000..a94c3f9
--- /dev/null
+++ b/Documentation/acpi/ssdt-overlays.txt
@@ -0,0 +1,94 @@ 
+
+In order to support ACPI open-ended hardware configurations (e.g. development
+boards) we need a way to augment the ACPI configuration provided by the firmware
+image. A common example is connecting sensors on I2C / SPI buses on development
+boards.
+
+Although this can be accomplished by creating a kernel platform driver or
+recompiling the firmware image with updated ACPI tables, neither is practical:
+the former proliferates board specific kernel code while the latter requires
+access to firmware tools which are often not publicly available.
+
+Because ACPI supports external references in AML code a more practical
+way to augment firmware ACPI configuration is by dynamically loading
+user defined SSDT tables that contain the board specific information.
+
+For example, to enumerate a Bosch BMA222E accelerometer on the I2C bus of the
+Minnowboard MAX development board exposed via the LSE connector [1], the
+following ASL code can be used:
+
+DefinitionBlock ("minnowmax.aml", "SSDT", 1, "Vendor", "Accel", 0x00000003)
+{
+    External (\_SB.I2C6, DeviceObj)
+
+    Scope (\_SB.I2C6)
+    {
+        Device (STAC)
+        {
+            Name (_ADR, Zero)
+            Name (_HID, "BMA222E")
+
+            Method (_CRS, 0, Serialized)
+            {
+                Name (RBUF, ResourceTemplate ()
+                {
+                    I2cSerialBus (0x0018, ControllerInitiated, 0x00061A80,
+                                  AddressingMode7Bit, "\\_SB.I2C6", 0x00,
+                                  ResourceConsumer, ,)
+                    GpioInt (Edge, ActiveHigh, Exclusive, PullDown, 0x0000,
+                             "\\_SB.GPO2", 0x00, ResourceConsumer, , )
+                    { // Pin list
+                        0
+                    }
+                })
+                Return (RBUF)
+            }
+        }
+    }
+}
+
+which can then be compiled to AML binary format:
+
+$ iasl minnowmax.asl
+
+Intel ACPI Component Architecture
+ASL Optimizing Compiler version 20140214-64 [Mar 29 2014]
+Copyright (c) 2000 - 2014 Intel Corporation
+
+ASL Input:     minnomax.asl - 30 lines, 614 bytes, 7 keywords
+AML Output:    minnowmax.aml - 165 bytes, 6 named objects, 1 executable opcodes
+
+[1] http://wiki.minnowboard.org/MinnowBoard_MAX#Low_Speed_Expansion_Connector_.28Top.29
+
+The resulting AML code can then be loaded by the kernel using one of the methods
+below.
+
+== Loading ACPI SSDTs from initrd ==
+
+This option allows loading of user defined SSDTs from initrd and it is useful
+when the system does not support EFI or when there is not enough EFI storage.
+
+It works in a similar way with initrd based ACPI tables overrides: SSDT aml code
+must be placed in the first, uncompressed, initrd under the
+"kernel/firmware/acpi/overlay" path. We use a different path than the initrd
+tables override to avoid conflicts with the override feature.
+
+Multiple files can be used and this will translate in loading multiple
+tables. Only tables with the SSDT signature will be loaded.
+
+Here is an example:
+
+# Add the raw ACPI tables to an uncompressed cpio archive.
+# They must be put into a /kernel/firmware/acpi/overlay directory inside the
+# cpio archive.
+# The uncompressed cpio archive must be the first.
+# Other, typically compressed cpio archives, must be
+# concatenated on top of the uncompressed one.
+mkdir -p kernel/firmware/acpi
+cp ssdt.aml kernel/firmware/acpi
+
+# Create the uncompressed cpio archive and concatenate the original initrd
+# on top:
+find kernel | cpio -H newc --create > /boot/instrumented_initrd
+cat /boot/initrd >>/boot/instrumented_initrd
+
diff --git a/drivers/acpi/bus.c b/drivers/acpi/bus.c
index 891c42d..5e0d076 100644
--- a/drivers/acpi/bus.c
+++ b/drivers/acpi/bus.c
@@ -37,9 +37,14 @@ 
 #include <acpi/apei.h>
 #include <linux/dmi.h>
 #include <linux/suspend.h>
+#include <linux/initrd.h>
+#include <linux/earlycpio.h>
 
 #include "internal.h"
 
+#undef pr_fmt
+#define pr_fmt(fmt) "ACPI: " fmt
+
 #define _COMPONENT		ACPI_BUS_COMPONENT
 ACPI_MODULE_NAME("bus");
 
@@ -863,6 +868,62 @@  static int __init acpi_bus_init_irq(void)
 	return 0;
 }
 
+void __init acpi_load_initrd_ssdts(void)
+{
+	void *data = (void *)initrd_start;
+	int size = initrd_end - initrd_start;
+	const char *path = "kernel/firmware/acpi/overlay";
+	long offset = 0;
+	struct cpio_data file;
+	struct acpi_table_header *header;
+	void *table;
+	acpi_status status;
+
+	while (true) {
+		file = find_cpio_data(path, data, size, &offset);
+		if (!file.data)
+			break;
+
+		data += offset;
+		size -= offset;
+
+		if (file.size < sizeof(struct acpi_table_header)) {
+			pr_err("initrd table smaller than ACPI header [%s%s]\n",
+			       path, file.name);
+			continue;
+		}
+
+		header = file.data;
+
+		if (file.size != header->length) {
+			pr_err("initrd file / table length mismatch [%s%s]\n",
+			       path, file.name);
+			continue;
+		}
+
+		if (memcmp(header->signature, ACPI_SIG_SSDT, 4)) {
+			pr_warn("skipping non-SSDT initrd table [%s%s]\n",
+				path, file.name);
+			continue;
+		}
+
+		table = kmemdup(file.data, file.size, GFP_KERNEL);
+		if (!table)
+			continue;
+
+		status = acpi_install_table((uintptr_t)table, 0);
+		if (ACPI_FAILURE(status)) {
+			pr_err("failed to install SSDT from initrd [%s%s]\n",
+			       path, file.name);
+			kfree(table);
+		}
+
+		pr_info("installed SSDT table found in initrd [%s%s][0x%x]\n",
+			path, file.name, header->length);
+		add_taint(TAINT_OVERLAY_ACPI_TABLE, LOCKDEP_STILL_OK);
+	}
+}
+
 /**
  * acpi_early_init - Initialize ACPICA and populate the ACPI namespace.
  *
@@ -911,6 +972,8 @@  void __init acpi_early_init(void)
 		goto error0;
 	}
 
+	acpi_load_initrd_ssdts();
+
 	status = acpi_load_tables();
 	if (ACPI_FAILURE(status)) {
 		printk(KERN_ERR PREFIX