acpi: Be more ACPI compliant when generating _UID
* Add function to generate unique _UID using CRC32 * Add function to write the _UID based on a device's ACPI path ACPI devices that have the same _HID must use different _UID. Linux doesn't care about _UID if it's not used. Windows 10 verifies the ACPI code on boot and BSODs if two devices with the same _HID share the same _UID. Fixes BSOD seen on Windows 10. Change-Id: I47cd5396060d325f9ce338afced6af021e7ff2b4 Signed-off-by: Patrick Rudolph <patrick.rudolph@9elements.com> Reviewed-on: https://review.coreboot.org/c/coreboot/+/37695 Tested-by: build bot (Jenkins) <no-reply@coreboot.org> Reviewed-by: Philipp Deppenwiese <zaolin.daisuki@gmail.com>
This commit is contained in:
parent
5c8ff794a8
commit
c83bab62b3
|
@ -2,6 +2,8 @@
|
||||||
|
|
||||||
This section contains documentation about coreboot on ACPI.
|
This section contains documentation about coreboot on ACPI.
|
||||||
|
|
||||||
|
- [SSDT UID generation](uid.md)
|
||||||
|
|
||||||
## GPIO
|
## GPIO
|
||||||
|
|
||||||
- [GPIO toggling in ACPI AML](gpio.md)
|
- [GPIO toggling in ACPI AML](gpio.md)
|
||||||
|
|
|
@ -0,0 +1,14 @@
|
||||||
|
# ACPI SSDT \_UID generation
|
||||||
|
|
||||||
|
According to the ACPI spec:
|
||||||
|
|
||||||
|
> The _UID must be unique across all devices with either a common _HID or _CID.
|
||||||
|
|
||||||
|
|
||||||
|
When generating SSDTs in coreboot the independent drivers don't know
|
||||||
|
which \_UID is already in use for a specific \_HID or \_CID. To generate
|
||||||
|
unique \_UIDs the ACPI device's path is hashed and used as ID. As every ACPI
|
||||||
|
device has a different path, the hash will be also different for every device.
|
||||||
|
|
||||||
|
Windows 10 verifies all devices with the same \_HID or \_CID and makes
|
||||||
|
sure that no \_UID is duplicated. If it is it'll BSOD.
|
|
@ -18,6 +18,8 @@
|
||||||
#include <device/device.h>
|
#include <device/device.h>
|
||||||
#include <device/path.h>
|
#include <device/path.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
#include <crc_byte.h>
|
||||||
|
|
||||||
#if CONFIG(GENERIC_GPIO_LIB)
|
#if CONFIG(GENERIC_GPIO_LIB)
|
||||||
#include <gpio.h>
|
#include <gpio.h>
|
||||||
#endif
|
#endif
|
||||||
|
@ -98,6 +100,19 @@ const char *acpi_device_hid(const struct device *dev)
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Generate unique ID based on the ACPI path.
|
||||||
|
* Collisions on the same _HID are possible but very unlikely.
|
||||||
|
*/
|
||||||
|
uint32_t acpi_device_uid(struct device *dev)
|
||||||
|
{
|
||||||
|
const char *path = acpi_device_path(dev);
|
||||||
|
if (!path)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return CRC(path, strlen(path), crc32_byte);
|
||||||
|
}
|
||||||
|
|
||||||
/* Recursive function to find the root device and print a path from there */
|
/* Recursive function to find the root device and print a path from there */
|
||||||
static ssize_t acpi_device_path_fill(const struct device *dev, char *buf,
|
static ssize_t acpi_device_path_fill(const struct device *dev, char *buf,
|
||||||
size_t buf_len, size_t cur)
|
size_t buf_len, size_t cur)
|
||||||
|
@ -192,6 +207,13 @@ int acpi_device_status(const struct device *dev)
|
||||||
return ACPI_STATUS_DEVICE_ALL_ON;
|
return ACPI_STATUS_DEVICE_ALL_ON;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Write the unique _UID based on ACPI device path. */
|
||||||
|
void acpi_device_write_uid(struct device *dev)
|
||||||
|
{
|
||||||
|
acpigen_write_name_integer("_UID", acpi_device_uid(dev));
|
||||||
|
}
|
||||||
|
|
||||||
/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
|
/* ACPI 6.1 section 6.4.3.6: Extended Interrupt Descriptor */
|
||||||
void acpi_device_write_interrupt(const struct acpi_irq *irq)
|
void acpi_device_write_interrupt(const struct acpi_irq *irq)
|
||||||
{
|
{
|
||||||
|
|
|
@ -62,10 +62,12 @@ struct acpi_dp {
|
||||||
struct device;
|
struct device;
|
||||||
const char *acpi_device_name(const struct device *dev);
|
const char *acpi_device_name(const struct device *dev);
|
||||||
const char *acpi_device_hid(const struct device *dev);
|
const char *acpi_device_hid(const struct device *dev);
|
||||||
|
uint32_t acpi_device_uid(struct device *dev);
|
||||||
const char *acpi_device_path(const struct device *dev);
|
const char *acpi_device_path(const struct device *dev);
|
||||||
const char *acpi_device_scope(const struct device *dev);
|
const char *acpi_device_scope(const struct device *dev);
|
||||||
const char *acpi_device_path_join(const struct device *dev, const char *name);
|
const char *acpi_device_path_join(const struct device *dev, const char *name);
|
||||||
int acpi_device_status(const struct device *dev);
|
int acpi_device_status(const struct device *dev);
|
||||||
|
void acpi_device_write_uid(struct device *dev);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* ACPI Descriptor for extended Interrupt()
|
* ACPI Descriptor for extended Interrupt()
|
||||||
|
|
|
@ -117,7 +117,7 @@ static void crb_tpm_fill_ssdt(struct device *dev)
|
||||||
acpigen_write_name_string("_HID", "MSFT0101");
|
acpigen_write_name_string("_HID", "MSFT0101");
|
||||||
acpigen_write_name_string("_CID", "MSFT0101");
|
acpigen_write_name_string("_CID", "MSFT0101");
|
||||||
|
|
||||||
acpigen_write_name_integer("_UID", 1);
|
acpi_device_write_uid(dev);
|
||||||
|
|
||||||
acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
|
acpigen_write_STA(ACPI_STATUS_DEVICE_ALL_ON);
|
||||||
|
|
||||||
|
|
|
@ -312,7 +312,8 @@ static void r8168_net_fill_ssdt(struct device *dev)
|
||||||
acpigen_write_scope(path);
|
acpigen_write_scope(path);
|
||||||
acpigen_write_device(acpi_device_name(dev));
|
acpigen_write_device(acpi_device_name(dev));
|
||||||
acpigen_write_name_string("_HID", R8168_ACPI_HID);
|
acpigen_write_name_string("_HID", R8168_ACPI_HID);
|
||||||
acpigen_write_name_integer("_UID", 0);
|
acpi_device_write_uid(dev);
|
||||||
|
|
||||||
if (dev->chip_ops)
|
if (dev->chip_ops)
|
||||||
acpigen_write_name_string("_DDN", dev->chip_ops->name);
|
acpigen_write_name_string("_DDN", dev->chip_ops->name);
|
||||||
|
|
||||||
|
|
|
@ -902,7 +902,7 @@ static void lpc_tpm_fill_ssdt(struct device *dev)
|
||||||
acpigen_write_name("_CID");
|
acpigen_write_name("_CID");
|
||||||
acpigen_emit_eisaid("PNP0C31");
|
acpigen_emit_eisaid("PNP0C31");
|
||||||
|
|
||||||
acpigen_write_name_integer("_UID", 1);
|
acpi_device_write_uid(dev);
|
||||||
|
|
||||||
u32 did_vid = tpm_read_did_vid(0);
|
u32 did_vid = tpm_read_did_vid(0);
|
||||||
if (did_vid > 0 && did_vid < 0xffffffff)
|
if (did_vid > 0 && did_vid < 0xffffffff)
|
||||||
|
|
|
@ -187,7 +187,8 @@ void generic_wifi_fill_ssdt(struct device *dev,
|
||||||
/* Device */
|
/* Device */
|
||||||
acpigen_write_scope(path);
|
acpigen_write_scope(path);
|
||||||
acpigen_write_device(acpi_device_name(dev));
|
acpigen_write_device(acpi_device_name(dev));
|
||||||
acpigen_write_name_integer("_UID", 0);
|
acpi_device_write_uid(dev);
|
||||||
|
|
||||||
if (dev->chip_ops)
|
if (dev->chip_ops)
|
||||||
acpigen_write_name_string("_DDN", dev->chip_ops->name);
|
acpigen_write_name_string("_DDN", dev->chip_ops->name);
|
||||||
|
|
||||||
|
|
|
@ -196,7 +196,8 @@ void superio_common_fill_ssdt_generator(struct device *dev)
|
||||||
/* Device */
|
/* Device */
|
||||||
acpigen_write_device(name);
|
acpigen_write_device(name);
|
||||||
|
|
||||||
acpigen_write_name_byte("_UID", 0);
|
acpi_device_write_uid(dev);
|
||||||
|
|
||||||
acpigen_write_name_byte("LDN", ldn);
|
acpigen_write_name_byte("LDN", ldn);
|
||||||
acpigen_write_name_byte("VLDN", vldn);
|
acpigen_write_name_byte("VLDN", vldn);
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue