[PATCH 5.3 regression fix] efi-stub: Fix get_efi_config_table on mixed-mode setups
Fix get_efi_config_table using the wrong structs when booting a 64 bit kernel on 32 bit firmware. Cc: Matthew Garrett Cc: Ard Biesheuvel Cc: Jarkko Sakkinen Fixes: 82d736ac56d7 ("Abstract out support for locating an EFI config table") Signed-off-by: Hans de Goede --- .../firmware/efi/libstub/efi-stub-helper.c| 38 +-- 1 file changed, 27 insertions(+), 11 deletions(-) diff --git a/drivers/firmware/efi/libstub/efi-stub-helper.c b/drivers/firmware/efi/libstub/efi-stub-helper.c index 1db780c0f07b..3caae7f2cf56 100644 --- a/drivers/firmware/efi/libstub/efi-stub-helper.c +++ b/drivers/firmware/efi/libstub/efi-stub-helper.c @@ -927,17 +927,33 @@ efi_status_t efi_exit_boot_services(efi_system_table_t *sys_table_arg, return status; } +#define GET_EFI_CONFIG_TABLE(bits) \ +static void *get_efi_config_table##bits(efi_system_table_t *_sys_table, \ + efi_guid_t guid)\ +{ \ + efi_system_table_##bits##_t *sys_table; \ + efi_config_table_##bits##_t *tables;\ + int i; \ + \ + sys_table = (typeof(sys_table))_sys_table; \ + tables = (typeof(tables))(unsigned long)sys_table->tables; \ + \ + for (i = 0; i < sys_table->nr_tables; i++) {\ + if (efi_guidcmp(tables[i].guid, guid) != 0) \ + continue; \ + \ + return (void *)(unsigned long)tables[i].table; \ + } \ + \ + return NULL;\ +} +GET_EFI_CONFIG_TABLE(32) +GET_EFI_CONFIG_TABLE(64) + void *get_efi_config_table(efi_system_table_t *sys_table, efi_guid_t guid) { - efi_config_table_t *tables = (efi_config_table_t *)sys_table->tables; - int i; - - for (i = 0; i < sys_table->nr_tables; i++) { - if (efi_guidcmp(tables[i].guid, guid) != 0) - continue; - - return (void *)tables[i].table; - } - - return NULL; + if (efi_is_64bit()) + return get_efi_config_table64(sys_table, guid); + else + return get_efi_config_table32(sys_table, guid); } -- 2.22.0
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 05-08-19 18:01, Ard Biesheuvel wrote: On Sun, 4 Aug 2019 at 19:12, Hans de Goede wrote: Hi, On 04-08-19 17:33, Ard Biesheuvel wrote: Hi Hans, On Sun, 4 Aug 2019 at 13:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks:SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Are you booting a 64-bit kernel on 32-bit firmware? Yes you are right, I must say that this is somewhat surprising most Cherry Trail devices do use 64 bit firmware (where as Bay Trail typically uses 32 bit). But I just checked efibootmgr output and it says it is booting: \EFI\FEDORA\SHIMIA32.EFI so yeah 32 bit firmware. Recent Fedora releases take care of this so seamlessly I did not even realize... OK, so we'll have to find out how this patch affects 64-bit code running on 32-bit firmware. The only EFI call in that patch is get_config_table(), which is not actually a EFI boot service call but a EFI stub helper that parses the config table array in the EFI system table. Ok, the problem indeed is the new get_efi_config_table() helper, it does not make any calls, but it does interpret some structs which have different sized members depending on if the firmware is 32 or 64 bit. I've prepared a patch fixing this which I will send out after this mail. Regards, Hans
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 07-08-19 22:13, Hans de Goede wrote: Hi, On 07-08-19 21:58, Hans de Goede wrote: Hi, On 05-08-19 18:01, Ard Biesheuvel wrote: On Sun, 4 Aug 2019 at 19:12, Hans de Goede wrote: Hi, On 04-08-19 17:33, Ard Biesheuvel wrote: Hi Hans, On Sun, 4 Aug 2019 at 13:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks: SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Are you booting a 64-bit kernel on 32-bit firmware? Yes you are right, I must say that this is somewhat surprising most Cherry Trail devices do use 64 bit firmware (where as Bay Trail typically uses 32 bit). But I just checked efibootmgr output and it says it is booting: \EFI\FEDORA\SHIMIA32.EFI so yeah 32 bit firmware. Recent Fedora releases take care of this so seamlessly I did not even realize... OK, so we'll have to find out how this patch affects 64-bit code running on 32-bit firmware. I was not sure this really is a 32 bit firmware issue, as I believed I saw 5.3 running fine on other 32 bit firmware devices, so I tried this on another device with 32 bit UEFI and you're right this is a 32 bit issue. The only EFI call in that patch is get_config_table(), which is not actually a EFI boot service call but a EFI stub helper that parses the config table array in the EFI system table. Well get_efi_config_table() is a new function in 5.3, introduced specifically for the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. It was introduced in commit 82d736ac56d7 ("Abstract out support for locating an EFI config table") and after taking a good look at this commit I'm pretty confident to say that the new get_efi_config_table() function is the problem, as it is broken in multiple ways. In itself the new get_efi_config_table() is just factoring out some code used in drivers/firmware/efi/libstub/fdt.c into a new helper for reuse and not making any functional changes to the factored out code. The problem is that the old code which it factors out contains a number of assumptions which are true in the get_fdt() context from which it was called but are not true when used in more generic code as is done from the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. There are 2 problems with the new get_efi_config_table() function: 1) sys_table->tables contains a physical address, we cannot just cast that to a pointer and deref it, it needs to be early_memremap-ed and then we deref the mapping. I'm somewhat amazed that this works at all for the 64 bit case, but apparently it does. 2) sys_table->tables points to either an array of either efi_config_table_64_t structd or an array of efi_config_table_32_t structs. efi_config_table_t is a generic type for storing information when parsing it should NOT be used for reading the actual tables as they come from the firmware when parsing! Now efi_config_table_t happens to be an exact match for efi_config_table_64_t when building an x86_64 kernel, so this happens to work for the 64 bit firmware case. The properway to deal with this would be to use the existing efi_config_parse_tables() functionality from drivers/firmwa
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 07-08-19 21:58, Hans de Goede wrote: Hi, On 05-08-19 18:01, Ard Biesheuvel wrote: On Sun, 4 Aug 2019 at 19:12, Hans de Goede wrote: Hi, On 04-08-19 17:33, Ard Biesheuvel wrote: Hi Hans, On Sun, 4 Aug 2019 at 13:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks: SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Are you booting a 64-bit kernel on 32-bit firmware? Yes you are right, I must say that this is somewhat surprising most Cherry Trail devices do use 64 bit firmware (where as Bay Trail typically uses 32 bit). But I just checked efibootmgr output and it says it is booting: \EFI\FEDORA\SHIMIA32.EFI so yeah 32 bit firmware. Recent Fedora releases take care of this so seamlessly I did not even realize... OK, so we'll have to find out how this patch affects 64-bit code running on 32-bit firmware. I was not sure this really is a 32 bit firmware issue, as I believed I saw 5.3 running fine on other 32 bit firmware devices, so I tried this on another device with 32 bit UEFI and you're right this is a 32 bit issue. The only EFI call in that patch is get_config_table(), which is not actually a EFI boot service call but a EFI stub helper that parses the config table array in the EFI system table. Well get_efi_config_table() is a new function in 5.3, introduced specifically for the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. It was introduced in commit 82d736ac56d7 ("Abstract out support for locating an EFI config table") and after taking a good look at this commit I'm pretty confident to say that the new get_efi_config_table() function is the problem, as it is broken in multiple ways. In itself the new get_efi_config_table() is just factoring out some code used in drivers/firmware/efi/libstub/fdt.c into a new helper for reuse and not making any functional changes to the factored out code. The problem is that the old code which it factors out contains a number of assumptions which are true in the get_fdt() context from which it was called but are not true when used in more generic code as is done from the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. There are 2 problems with the new get_efi_config_table() function: 1) sys_table->tables contains a physical address, we cannot just cast that to a pointer and deref it, it needs to be early_memremap-ed and then we deref the mapping. I'm somewhat amazed that this works at all for the 64 bit case, but apparently it does. 2) sys_table->tables points to either an array of either efi_config_table_64_t structd or an array of efi_config_table_32_t structs. efi_config_table_t is a generic type for storing information when parsing it should NOT be used for reading the actual tables as they come from the firmware when parsing! Now efi_config_table_t happens to be an exact match for efi_config_table_64_t when building an x86_64 kernel, so this happens to work for the 64 bit firmware case. The properway to deal with this would be to use the existing efi_config_parse_tables() functionality from drivers/firmware/efi/efi.c by adding entry for the LINUX_EFI_TPM_F
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 05-08-19 18:01, Ard Biesheuvel wrote: On Sun, 4 Aug 2019 at 19:12, Hans de Goede wrote: Hi, On 04-08-19 17:33, Ard Biesheuvel wrote: Hi Hans, On Sun, 4 Aug 2019 at 13:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks:SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Are you booting a 64-bit kernel on 32-bit firmware? Yes you are right, I must say that this is somewhat surprising most Cherry Trail devices do use 64 bit firmware (where as Bay Trail typically uses 32 bit). But I just checked efibootmgr output and it says it is booting: \EFI\FEDORA\SHIMIA32.EFI so yeah 32 bit firmware. Recent Fedora releases take care of this so seamlessly I did not even realize... OK, so we'll have to find out how this patch affects 64-bit code running on 32-bit firmware. I was not sure this really is a 32 bit firmware issue, as I believed I saw 5.3 running fine on other 32 bit firmware devices, so I tried this on another device with 32 bit UEFI and you're right this is a 32 bit issue. The only EFI call in that patch is get_config_table(), which is not actually a EFI boot service call but a EFI stub helper that parses the config table array in the EFI system table. Well get_efi_config_table() is a new function in 5.3, introduced specifically for the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. It was introduced in commit 82d736ac56d7 ("Abstract out support for locating an EFI config table") and after taking a good look at this commit I'm pretty confident to say that the new get_efi_config_table() function is the problem, as it is broken in multiple ways. In itself the new get_efi_config_table() is just factoring out some code used in drivers/firmware/efi/libstub/fdt.c into a new helper for reuse and not making any functional changes to the factored out code. The problem is that the old code which it factors out contains a number of assumptions which are true in the get_fdt() context from which it was called but are not true when used in more generic code as is done from the 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") commit. There are 2 problems with the new get_efi_config_table() function: 1) sys_table->tables contains a physical address, we cannot just cast that to a pointer and deref it, it needs to be early_memremap-ed and then we deref the mapping. I'm somewhat amazed that this works at all for the 64 bit case, but apparently it does. 2) sys_table->tables points to either an array of either efi_config_table_64_t structd or an array of efi_config_table_32_t structs. efi_config_table_t is a generic type for storing information when parsing it should NOT be used for reading the actual tables as they come from the firmware when parsing! Now efi_config_table_t happens to be an exact match for efi_config_table_64_t when building an x86_64 kernel, so this happens to work for the 64 bit firmware case. The properway to deal with this would be to use the existing efi_config_parse_tables() functionality from drivers/firmware/efi/efi.c by adding entry for the LINUX_EFI_TPM_FINAL_LOG_GUID to the common_tables[] array in
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 06-08-19 17:53, Chris Coulson wrote: Hi, On 04/08/2019 11:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks: SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Regards, Hans Do you think this might be the same issue as https://marc.info/?l=linux-integrity&m=155968949020639 <https://marc.info/?l=linux-integrity&m=155968949020639&w=2>? I was hoping it would be the same issue, so I tested a 5.3 kernel with that patch added, but unfortunately it still crashes on the Irbis TW90. Regards, Hans
Re: 5.3 boot regression caused by 5.3 TPM changes
Hi, On 04-08-19 17:33, Ard Biesheuvel wrote: Hi Hans, On Sun, 4 Aug 2019 at 13:00, Hans de Goede wrote: Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks:SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Are you booting a 64-bit kernel on 32-bit firmware? Yes you are right, I must say that this is somewhat surprising most Cherry Trail devices do use 64 bit firmware (where as Bay Trail typically uses 32 bit). But I just checked efibootmgr output and it says it is booting: \EFI\FEDORA\SHIMIA32.EFI so yeah 32 bit firmware. Recent Fedora releases take care of this so seamlessly I did not even realize... Regards, Hans
5.3 boot regression caused by 5.3 TPM changes
Hi All, While testing 5.3-rc2 on an Irbis TW90 Intel Cherry Trail based tablet I noticed that it does not boot on this device. A git bisect points to commit 166a2809d65b ("tpm: Don't duplicate events from the final event log in the TCG2 log") And I can confirm that reverting just that single commit makes the TW90 boot again. This machine uses AptIO firmware with base component versions of: UEFI 2.4 PI 1.3. I've tried to reproduce the problem on a Teclast X80 Pro which is also CHT based and also uses AptIO firmware with the same base components. But it does not reproduce there. Neither does the problem reproduce on a CHT tablet using InsideH20 based firmware. Note that these devices have a software/firmware TPM-2.0 implementation, they do not have an actual TPM chip. Comparing TPM firmware setting between the 2 AptIO based tablets the settings are identical, but the troublesome TW90 does have some more setting then the X80, it has the following settings which are not shown on the X80: Active PCR banks: SHA-1 (read only) Available PCR banks:SHA-1,SHA256 (read only) TPM2.0 UEFI SPEC version: TCG_2 (other possible setting: TCG_1_2 Physical Presence SPEC ver: 1.2 (other possible setting: 1.3) I have the feeling that at least the first 2 indicate that the previous win10 installation has actually used the TPM, where as on the X80 the TPM is uninitialized. Note this is just a hunch I could be completely wrong. I would be happy to run any commands to try and debug this or to build a kernel with some patches to gather more info. Note any kernel patches to printk some debug stuff need to be based on 5.3 with 166a2809d65b reverted, without that reverted the device will not boot, and thus I cannot collect logs without it reverted. Regards, Hans
[PATCH] efi/bgrt: Drop BGRT status field reserved bits check
Starting with ACPI 6.2 bits 1 and 2 of the BGRT status field are no longer reserved. These bits are now used to indicate if the image needs to be rotated before being displayed. The first device using these bits has now shown up (the GPD MicroPC) and the reserved bits check causes us to reject the valid BGRT table on this device. Rather then changing the reserved bits check, allowing only the 2 new bits, instead just completely remove it so that we do not end up with a similar problem when more bits are added in the future. Signed-off-by: Hans de Goede --- drivers/firmware/efi/efi-bgrt.c | 5 - 1 file changed, 5 deletions(-) diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index a2384184a7de..b07c17643210 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -47,11 +47,6 @@ void __init efi_bgrt_init(struct acpi_table_header *table) bgrt->version); goto out; } - if (bgrt->status & 0xfe) { - pr_notice("Ignoring BGRT: reserved status bits are non-zero %u\n", - bgrt->status); - goto out; - } if (bgrt->image_type != 0) { pr_notice("Ignoring BGRT: invalid image type %u (expected 0)\n", bgrt->image_type); -- 2.21.0
[PATCH v2] efi/x86: Call efi_parse_options() from efi_main()
Before this commit we were only calling efi_parse_options() from make_boot_params(), but make_boot_params() only gets called if the kernel gets booted directly as an EFI executable. So when booted through e.g. grub we ended up not parsing the commandline in the boot code. This makes the drivers/firmware/efi/libstub code ignore the "quiet" commandline argument resulting in the following message being printed: "EFI stub: UEFI Secure Boot is enabled." Despite the quiet request. This commits adds an extra call to efi_parse_options() to efi_main() to make sure that the options are always processed. This fixes quiet not working. This also fixes the libstub code ignoring nokaslr and efi=nochunk. Reported-by: Peter Robinson Signed-off-by: Hans de Goede --- Changes in v2: -Fix a compiler warning on 32 bit builds about casting a non pointer sized integer to a pointer --- arch/x86/boot/compressed/eboot.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 1458b1700fc7..8b4c5e001157 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -738,6 +738,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) struct desc_struct *desc; void *handle; efi_system_table_t *_table; + unsigned long cmdline_paddr; efi_early = c; @@ -755,6 +756,15 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) else setup_boot_services32(efi_early); + /* +* make_boot_params() may have been called before efi_main(), in which +* case this is the second time we parse the cmdline. This is ok, +* parsing the cmdline multiple times does not have side-effects. +*/ + cmdline_paddr = ((u64)hdr->cmd_line_ptr | +((u64)boot_params->ext_cmd_line_ptr << 32)); + efi_parse_options((char *)cmdline_paddr); + /* * If the boot loader gave us a value for secure_boot then we use that, * otherwise we ask the BIOS. -- 2.19.0.rc0
Re: [PATCH] efi/x86: Call efi_parse_options() from efi_main()
Hi, On 12-09-18 17:06, Ard Biesheuvel wrote: On 12 September 2018 at 15:18, Hans de Goede wrote: Before this commit we were only calling efi_parse_options() from make_boot_params(), but make_boot_params() only gets called if the kernel gets booted directly as an EFI executable. So when booted through e.g. grub we ended up not parsing the commandline in the boot code. This makes the drivers/firmware/efi/libstub code ignore the "quiet" commandline argument resulting in the following message being printed: "EFI stub: UEFI Secure Boot is enabled." Despite the quiet request. This commits adds an extra call to efi_parse_options() to efi_main() to make sure that the options are always processed. This fixes quiet not working. This also fixes the libstub code ignoring nokaslr and efi=nochunk. Reported-by: Peter Robinson Signed-off-by: Hans de Goede --- arch/x86/boot/compressed/eboot.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index aaabf979cbd9..a4c85d37adc9 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -738,6 +738,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) struct desc_struct *desc; void *handle; efi_system_table_t *_table; + const char *cmdline_ptr; efi_early = c; @@ -755,6 +756,15 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) else setup_boot_services32(efi_early); + /* +* make_boot_params() may have been called before efi_main(), in which +* case this is the second time we parse the cmdline. This is ok, +* parsing the cmdline multiple times does not have side-effects. +*/ + cmdline_ptr = (const char *)((u64)hdr->cmd_line_ptr | + ((u64)boot_params->ext_cmd_line_ptr << 32)); + efi_parse_options(cmdline_ptr); + This triggers a warning on 32-bit because sizeof(void*) != sizeof(u64) Grumble, ok so looking at what other code accessing hdr->cmd_line_ptr + boot_params->ext_cmd_line_ptr is most code seems to store it in an unsigned long. So here is what I suggest for v2: --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -738,6 +738,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) struct desc_struct *desc; void *handle; efi_system_table_t *_table; + unsigned long cmdline_paddr; efi_early = c; @@ -755,6 +756,15 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) else setup_boot_services32(efi_early); + /* +* make_boot_params() may have been called before efi_main(), in which +* case this is the second time we parse the cmdline. This is ok, +* parsing the cmdline multiple times does not have side-effects. +*/ + cmdline_paddr = ((u64)hdr->cmd_line_ptr | +((u64)boot_params->ext_cmd_line_ptr << 32)); + efi_parse_options((char *)cmdline_paddr); + /* * If the boot loader gave us a value for secure_boot then we use that, * otherwise we ask the BIOS. If that looks ok to you I will send out a proper v2 with this. Regards, Hans
[PATCH] efi/x86: Call efi_parse_options() from efi_main()
Before this commit we were only calling efi_parse_options() from make_boot_params(), but make_boot_params() only gets called if the kernel gets booted directly as an EFI executable. So when booted through e.g. grub we ended up not parsing the commandline in the boot code. This makes the drivers/firmware/efi/libstub code ignore the "quiet" commandline argument resulting in the following message being printed: "EFI stub: UEFI Secure Boot is enabled." Despite the quiet request. This commits adds an extra call to efi_parse_options() to efi_main() to make sure that the options are always processed. This fixes quiet not working. This also fixes the libstub code ignoring nokaslr and efi=nochunk. Reported-by: Peter Robinson Signed-off-by: Hans de Goede --- arch/x86/boot/compressed/eboot.c | 10 ++ 1 file changed, 10 insertions(+) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index aaabf979cbd9..a4c85d37adc9 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -738,6 +738,7 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) struct desc_struct *desc; void *handle; efi_system_table_t *_table; + const char *cmdline_ptr; efi_early = c; @@ -755,6 +756,15 @@ efi_main(struct efi_config *c, struct boot_params *boot_params) else setup_boot_services32(efi_early); + /* +* make_boot_params() may have been called before efi_main(), in which +* case this is the second time we parse the cmdline. This is ok, +* parsing the cmdline multiple times does not have side-effects. +*/ + cmdline_ptr = (const char *)((u64)hdr->cmd_line_ptr | + ((u64)boot_params->ext_cmd_line_ptr << 32)); + efi_parse_options(cmdline_ptr); + /* * If the boot loader gave us a value for secure_boot then we use that, * otherwise we ask the BIOS. -- 2.19.0.rc0
Re: [REGRESSION] boot-screen override by "34db50e55656 efifb: Copy the ACPI BGRT"
Hi, On 03-09-18 17:11, David Herrmann wrote: Hey On Mon, Sep 3, 2018 at 4:47 PM Hans de Goede wrote: Hi, On 03-09-18 16:16, Bartlomiej Zolnierkiewicz wrote: Hi, On Monday, September 03, 2018 03:23:38 PM David Herrmann wrote: Hey Since this commit: 34db50e55656 efifb: Copy the ACPI BGRT the kernel will override boot-splashs unasked. This breaks the graphical boot-process on our setups. In particular, we have a setup where an efi-boot-entry draws the early boot-splash on-screen, then hands-over to the linux-kernel + initrd. The boot-splash daemon in the initrd then takes over control of possible animations. With the mentioned commit compiled in, the kernel will redraw the firmware logo on screen at a random time without any way to intervene. You have CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y (the deferred console takeover support introduced in v4,19-rc1). I assume that this is intended? What is the intention of this commit? Why is the kernel re-drawing the firmware logo unasked? If someone during the boot-process draws content on the screen, I would prefer if the kernel does not clear that on driver load. +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ +defined CONFIG_ACPI_BGRT ... +static void efifb_show_boot_graphics(struct fb_info *info) ... +#else +static inline void efifb_show_boot_graphics(struct fb_info *info) {} +#endif Can we either provide an option to disable this feature, or revert the commit? Hans? We use the ACPI bgrt extension to get the logo to draw and then draw it since some devices rely on the OS to draw it and otherwise we just end up with a blackscreen when doing silent / flickerfree boot. Ideally you would be able to get your vendor to put the logo in firmware in the ACPI bgrt extension, then you also do not need to play any tricks with an EFI binary drawing your own logo. But I can understand if you don't have control over this, so you need to do this with the EFI binary trick. I can also understand that you want to use deferred console takeover in a setup like yours to avoid fbcon messing up what is on the display during boot, that is exactly what it is for. So I think a reasonable approach here is to add a kernel commandline option, say: video=efifb:nobgrt David, would that work for you? That would be perfect! Ok, I just send out a patch for this with you in the Cc. Sorry for taking a bit long to write the patch. Regards, Hans
Re: [REGRESSION] boot-screen override by "34db50e55656 efifb: Copy the ACPI BGRT"
Hi, On 03-09-18 16:16, Bartlomiej Zolnierkiewicz wrote: Hi, On Monday, September 03, 2018 03:23:38 PM David Herrmann wrote: Hey Since this commit: 34db50e55656 efifb: Copy the ACPI BGRT the kernel will override boot-splashs unasked. This breaks the graphical boot-process on our setups. In particular, we have a setup where an efi-boot-entry draws the early boot-splash on-screen, then hands-over to the linux-kernel + initrd. The boot-splash daemon in the initrd then takes over control of possible animations. With the mentioned commit compiled in, the kernel will redraw the firmware logo on screen at a random time without any way to intervene. You have CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER=y (the deferred console takeover support introduced in v4,19-rc1). I assume that this is intended? What is the intention of this commit? Why is the kernel re-drawing the firmware logo unasked? If someone during the boot-process draws content on the screen, I would prefer if the kernel does not clear that on driver load. +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ +defined CONFIG_ACPI_BGRT ... +static void efifb_show_boot_graphics(struct fb_info *info) ... +#else +static inline void efifb_show_boot_graphics(struct fb_info *info) {} +#endif Can we either provide an option to disable this feature, or revert the commit? Hans? We use the ACPI bgrt extension to get the logo to draw and then draw it since some devices rely on the OS to draw it and otherwise we just end up with a blackscreen when doing silent / flickerfree boot. Ideally you would be able to get your vendor to put the logo in firmware in the ACPI bgrt extension, then you also do not need to play any tricks with an EFI binary drawing your own logo. But I can understand if you don't have control over this, so you need to do this with the EFI binary trick. I can also understand that you want to use deferred console takeover in a setup like yours to avoid fbcon messing up what is on the display during boot, that is exactly what it is for. So I think a reasonable approach here is to add a kernel commandline option, say: video=efifb:nobgrt David, would that work for you? Regards, Hans
Re: [PATCH 0/6] efi/x86 mixed mode cleanups
Hi, On 12-07-18 14:21, Ard Biesheuvel wrote: This series contains some fixes and cleanups for mixed-mode UEFI on x86. Patch #1 adds the missing locking in the runtime service wrapper code for mixed mode. This was found by inspection rather than having been reported but could be a candidate for -stable nonetheless. Patch #2 merges the remaining 32/64-bit specific parts of the setup_efi_pci routine. Patches #3 and #4 do the same for the UGA draw protocol discovery routines. Patch #5 fixes a latent bug in the UGA draw code. Patch #6 helps unused code paths to be optimized away on configurations that don't need them (32-bit only and 64-bit only) I've given a kernel with these patches a quick spin running in mixed mode on a Bay Trail based tablet: Tested-by: Hans de Goede Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [GIT PULL 0/1] EFI mixed mode fix for v4.18
Hi, On 11-07-18 12:13, Ingo Molnar wrote: * Ard Biesheuvel wrote: The following changes since commit 1e4b044d22517cae7047c99038abb23243ca: Linux 4.18-rc4 (2018-07-08 16:34:02 -0700) are available in the Git repository at: git://git.kernel.org/pub/scm/linux/kernel/git/efi/efi.git tags/efi-urgent for you to fetch changes up to d7f2e972e702d329fe11d6956df99dfc31211c25: efi/x86: remove pointless call to PciIo->Attributes() (2018-07-11 10:52:46 +0200) A single fix for the x86 PCI I/O protocol handling code that got broken for mixed mode (64-bit Linux/x86 on 32-bit UEFI) after a fix was applied in -rc2 to fix it for ordinary 64-bit Linux/x86. Just curious, because it's unclear from the changelog, what was the symptom, a boot hang, instant reboot, or some other misbehavior? Also, what's the scope of the fix: were all 64-bit on 32-bit UEFI mixed-mode bootups affected, or only a certain subset? The problem was a reboot (resulting in a boot loop). I may have tested this on multiple Bay Trail based devices, I don't remember but it was an issue on Bay Trail devices, which typically use a 32 bit UEFI even though they have a 64 bit capable CPU. There are some rare Bay Trail devices with a 64 bit UEFI but they are the exception. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2 1/2] efi/bgrt: Drop __initdata from bgrt_image_size
Bartlomiej, Now that the fbcon deferred console takeover patches have been merged I believe this series can be merged too ? Note the first patch has an ack from Ard for merging the 1 line efi change through the fbdev tree. Regards, Hans On 18-06-18 17:13, Hans de Goede wrote: bgrt_image_size is necessary to (optionally) show the boot graphics from the efifb code. The efifb driver is a platform driver, using a normal driver probe() driver callback. So even though it is always builtin it cannot reference __initdata. Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- drivers/firmware/efi/efi-bgrt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 50793fda7819..b22ccfb0c991 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -20,7 +20,7 @@ #include struct acpi_table_bgrt bgrt_tab; -size_t __initdata bgrt_image_size; +size_t bgrt_image_size; struct bmp_header { u16 id; -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [RFC PATCH] x86/efi: remove pointless call to PciIo->Attributes()
Hi, On 24-06-18 19:29, Ard Biesheuvel wrote: When it was first introduced, the EFI stub code that copies the contents of PCI option ROMs originally only intended to do so if the EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM attribute was *not* set. The reason was that the UEFI spec permits PCI option ROM images to be provided by the platform directly, rather than via the ROM BAR, and in this case, the OS can only access them at runtime if they are preserved at boot time by copying them from the areas described by PciIo->RomImage and PciIo->RomSize. However, it implemented this check erroneously, as can be seen in commit dd5fc854de5fd ("EFI: Stash ROMs if they're not in the PCI BAR"): if (!attributes & EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM) continue; and given that the numeric value of EFI_PCI_IO_ATTRIBUTE_EMBEDDED_ROM is 0x4000, this condition never becomes true, and so the option ROMs were copied unconditionally. This was spotted and 'fixed' by commit 886d751a2ea99a160 ("x86, efi: correct precedence of operators in setup_efi_pci"), but inadvertently inverted the logic at the same time, defeating the purpose of the code, since it now only preserves option ROM images that can be read from the ROM BAR as well. Unsurprisingly, this broke some systems, and so the check was removed entirely in commit 739701888f5d ("x86, efi: remove attribute check from setup_efi_pci"). It is debatable whether this check should have been included in the first place, since the option ROM image provided to the UEFI driver by the firmware may be different from the one that is actually present in the card's flash ROM, and so whatever PciIo->RomImage points at should be preferred regardless of whether the attribute is set. As this was the only use of the attributes field, we can remove the call to PciIo->Attributes() entirely, which is especially nice because its prototype involves uint64_t type by-value arguments which the EFI mixed mode has trouble dealing with. Cc: Wilfried Klaebe Cc: Ingo Molnar Cc: Thomas Gleixner Cc: Lukas Wunner Cc: Hans de Goede Signed-off-by: Ard Biesheuvel I can confirm that this fixes the mixed mode UEFI boot issues: Tested-by: Hans de Goede Regards, Hans --- This should fix the mixed mode issue reported by Hans after my fix for 64-bit native mode was included in v4.18-rc2. arch/x86/boot/compressed/eboot.c | 12 +++- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index e57665b4ba1c..e98522ea6f09 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -114,18 +114,12 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) struct pci_setup_rom *rom = NULL; efi_status_t status; unsigned long size; - uint64_t attributes, romsize; + uint64_t romsize; void *romimage; - status = efi_call_proto(efi_pci_io_protocol, attributes, pci, - EfiPciIoAttributeOperationGet, 0ULL, - &attributes); - if (status != EFI_SUCCESS) - return status; - /* -* Some firmware images contain EFI function pointers at the place where the -* romimage and romsize fields are supposed to be. Typically the EFI +* Some firmware images contain EFI function pointers at the place where +* the romimage and romsize fields are supposed to be. Typically the EFI * code is mapped at high addresses, translating to an unrealistically * large romsize. The UEFI spec limits the size of option ROMs to 16 * MiB so we reject any ROMs over 16 MiB in size to catch this. -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] x86/efi: Fix incorrect invocation of PciIo->Attributes()
Hi Ard, On 23-06-18 23:19, Ard Biesheuvel wrote: Commit 2c3625cb9fa2 efi/x86: Fold __setup_efi_pci32() and __setup_efi_pci64() into one function merged the two versions of __setup_efi_pciXX(), without taking into account that the 32-bit version used a rather dodgy trick to pass an immediate 0 constant as argument for a uint64_t parameter. The issue is caused by the fact that on x86, UEFI protocol method calls are redirected via struct efi_config::call(), which is a variadic function, and so the compiler has to infer the types of the parameters from the arguments rather than from the prototype. As the 32-bit x86 calling convention passes arguments via the stack, passing the unqualified constant 0 twice is the same as passing 0ULL, which is why the 32-bit code in __setup_efi_pci32() contained the following call: status = efi_early->call(pci->attributes, pci, EfiPciIoAttributeOperationGet, 0, 0, &attributes); to invoke this UEFI protocol method: typedef EFI_STATUS (EFIAPI *EFI_PCI_IO_PROTOCOL_ATTRIBUTES) ( IN EFI_PCI_IO_PROTOCOL *This, IN EFI_PCI_IO_PROTOCOL_ATTRIBUTE_OPERATION Operation, IN UINT64 Attributes, OUT UINT64 *Result OPTIONAL ); After the merge, we inadvertently ended up with this version for both 32-bit and 64-bit builds, breaking the latter. So replace the two zeroes with the explicitly typed constant 0ULL, which works as expected on both 32-bit and 64-bit builds. Reported-by: Wilfried Klaebe Tested-by: Wilfried Klaebe Signed-off-by: Ard Biesheuvel --- Wilfried tested the 64-bit build, and I checked the generated assembly of a 32-bit build with and without this patch, and they are identical. Ard, thank you for Cc-ing me on this. I've tested a 64 bit kernel build on a 32 bit UEFI firmware (so mixed mode) and this patch causes a reboot loop there. I do get grub (no surprise there as grub is unchanged), but as soon as the kernel loads the device resets. So I think we need some special casing there to deal with a 64 bit kernel calling into 32 bit UEFI. Regards, Hans Ingo, mind applying this directly? Thanks. arch/x86/boot/compressed/eboot.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index a8a8642d2b0b..e57665b4ba1c 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -118,7 +118,7 @@ __setup_efi_pci(efi_pci_io_protocol_t *pci, struct pci_setup_rom **__rom) void *romimage; status = efi_call_proto(efi_pci_io_protocol, attributes, pci, - EfiPciIoAttributeOperationGet, 0, 0, + EfiPciIoAttributeOperationGet, 0ULL, &attributes); if (status != EFI_SUCCESS) return status; -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] efi/libstub/tpm: Initialize efi_physical_addr_t vars to zero for mixed mode
Hi, On 21-06-18 09:57, Ard Biesheuvel wrote: On 21 June 2018 at 09:42, Hans de Goede wrote: Commit 79832f0b5f71 ("efi/libstub/tpm: Initialize pointer variables to zero for mixed mode") fixes a problem with the tpm code on mixed mode (64 bit kernel on 32 bit UEFI), where 64-bit pointer variables are not fully initialized by the 32-bit EFI code. A simlar problem applies to the efi_physical_addr_t variables which are written by the get_event_log EFI call. Even though efi_physical_addr_t is 64 bit everywhere it seems that some 32 bit UEFI implementations only fill in the lower 32 bits when passed a pointer to an efi_physical_addr_t to fill. This commit initializes these to 0 to, to ensure the upper 32 bits are 0 in mixed mode. This fixes recent kernels sometimes hanging during early boot on mixed mode UEFI systems. Signed-off-by: Hans de Goede --- Changes in v2: -Change commit message to reflect that efi_physical_addr_t is 64 bit everywhere and some firmwares only filling the lower 32 bits is somewhat unexpected Thanks Hans Queued in efi/next Thanks, I just realized I forgot to add a "Cc: sta...@vger.kernel.org", the problem of some BYT machines not booting about 50% of the times was introduced in 4.17. Given that this is a bugfix for this, it would be good to get this added to 4.18-rc# and 4.17.x Regards, Hans --- drivers/firmware/efi/libstub/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index caa37a6dd9d4..a90b0b8fc69a 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -64,7 +64,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; - efi_physical_addr_t log_location, log_last_entry; + efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] efi/libstub/tpm: Initialize efi_physical_addr_t vars to zero for mixed mode
Commit 79832f0b5f71 ("efi/libstub/tpm: Initialize pointer variables to zero for mixed mode") fixes a problem with the tpm code on mixed mode (64 bit kernel on 32 bit UEFI), where 64-bit pointer variables are not fully initialized by the 32-bit EFI code. A simlar problem applies to the efi_physical_addr_t variables which are written by the get_event_log EFI call. Even though efi_physical_addr_t is 64 bit everywhere it seems that some 32 bit UEFI implementations only fill in the lower 32 bits when passed a pointer to an efi_physical_addr_t to fill. This commit initializes these to 0 to, to ensure the upper 32 bits are 0 in mixed mode. This fixes recent kernels sometimes hanging during early boot on mixed mode UEFI systems. Signed-off-by: Hans de Goede --- Changes in v2: -Change commit message to reflect that efi_physical_addr_t is 64 bit everywhere and some firmwares only filling the lower 32 bits is somewhat unexpected --- drivers/firmware/efi/libstub/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index caa37a6dd9d4..a90b0b8fc69a 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -64,7 +64,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; - efi_physical_addr_t log_location, log_last_entry; + efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH] efi/libstub/tpm: Initialize efi_physical_addr_t vars to zero for mixed mode
Hi, On 20-06-18 09:49, Ard Biesheuvel wrote: On 19 June 2018 at 21:50, Hans de Goede wrote: Commit 79832f0b5f71 ("efi/libstub/tpm: Initialize pointer variables to zero for mixed mode") fixes a problem with the tpm code on mixed mode (64 bit kernel on 32 bit UEFI), where 64-bit pointer variables are not fully initialized by the 32-bit EFI code. The same problem applies to the efi_physical_addr_t variables which are written by the get_event_log EFI call. This commit initializes these to 0 to, to ensure the upper 32 bits are 0 in mixed mode. This fixes recent kernels sometimes hanging during early boot on mixed mode UEFI systems. efi_physical_addr_t is always a 64-bit type, regardless of mixed mode, so this smells like buggy firmware. That is true. I would not be surprised if this is buggy firmware, this is the infamous Insyde firmware for Bay Trail devices which is weird and special in many ways as it was first written to bring up Android and then modified to run Windows later (I think / it seems). At least the DSDT tables have Android and Windows specific bits and some firmware-s have a setup switch to select which bits get activated, while others try to autodetect which OS they are going to boot. Anyways I will do a v2 with a fixed commit message taking into account that efi_physical_addr_t is always a 64-bit type. Is the issue 100% reproducible? Without this change my Asus T100TA boots about once every other time, maybe even worse like once every 3 boots. When it does not boot most of the time it hangs in early boot (before the efifb driver initializes), sometimes it hangs only for a minute or 2 and then reboots. With this change it boots 10 out 10 times, both after a power off + wait 10 sec + on and on regular reboots. Regards, Hans Signed-off-by: Hans de Goede --- drivers/firmware/efi/libstub/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index caa37a6dd9d4..a90b0b8fc69a 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -64,7 +64,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; - efi_physical_addr_t log_location, log_last_entry; + efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] efi/libstub/tpm: Initialize efi_physical_addr_t vars to zero for mixed mode
Commit 79832f0b5f71 ("efi/libstub/tpm: Initialize pointer variables to zero for mixed mode") fixes a problem with the tpm code on mixed mode (64 bit kernel on 32 bit UEFI), where 64-bit pointer variables are not fully initialized by the 32-bit EFI code. The same problem applies to the efi_physical_addr_t variables which are written by the get_event_log EFI call. This commit initializes these to 0 to, to ensure the upper 32 bits are 0 in mixed mode. This fixes recent kernels sometimes hanging during early boot on mixed mode UEFI systems. Signed-off-by: Hans de Goede --- drivers/firmware/efi/libstub/tpm.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index caa37a6dd9d4..a90b0b8fc69a 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -64,7 +64,7 @@ static void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_guid_t tcg2_guid = EFI_TCG2_PROTOCOL_GUID; efi_guid_t linux_eventlog_guid = LINUX_EFI_TPM_EVENT_LOG_GUID; efi_status_t status; - efi_physical_addr_t log_location, log_last_entry; + efi_physical_addr_t log_location = 0, log_last_entry = 0; struct linux_efi_tpm_eventlog *log_tbl = NULL; unsigned long first_entry_addr, last_entry_addr; size_t log_size, last_entry_size; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/2] efifb: Copy the ACPI BGRT boot graphics to the framebuffer
On systems where fbcon is configured for deferred console takeover, the intend is for the framebuffer to show the boot graphics (e.g a vendor logo) until some message (e.g. an error) is printed or a graphical session takes over. Some firmware relies on the OS to show the boot graphics. This patch adds support to efifb to show the boot graphics and automatically enables this when fbcon is configured for deferred console takeover. Signed-off-by: Hans de Goede --- Changes in v2: -Simplify the comment about acpi_bgrt.status -Clear the parts of the screen which don't contain the logo to black (memset to 0), rather then leaving them as is --- drivers/video/fbdev/efifb.c | 140 1 file changed, 140 insertions(+) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 46a4484e3da7..fa01eecc0a55 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -9,16 +9,39 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include /* For drm_get_panel_orientation_quirk */ #include /* For DRM_MODE_PANEL_ORIENTATION_* */ +struct bmp_file_header { + u16 id; + u32 file_size; + u32 reserved; + u32 bitmap_offset; +} __packed; + +struct bmp_dib_header { + u32 dib_header_size; + s32 width; + s32 height; + u16 planes; + u16 bpp; + u32 compression; + u32 bitmap_size; + u32 horz_resolution; + u32 vert_resolution; + u32 colors_used; + u32 colors_important; +} __packed; + static bool request_mem_succeeded = false; static bool nowc = false; @@ -66,6 +89,121 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ +defined CONFIG_ACPI_BGRT +static void efifb_copy_bmp(u8 *src, u32 *dst, int width, struct screen_info *si) +{ + u8 r, g, b; + + while (width--) { + b = *src++; + g = *src++; + r = *src++; + *dst++ = (r << si->red_pos) | +(g << si->green_pos) | +(b << si->blue_pos); + } +} + +static void efifb_show_boot_graphics(struct fb_info *info) +{ + u32 bmp_width, bmp_height, bmp_pitch, screen_pitch, dst_x, y, src_y; + struct screen_info *si = &screen_info; + struct bmp_file_header *file_header; + struct bmp_dib_header *dib_header; + void *bgrt_image = NULL; + u8 *dst = info->screen_base; + + if (!bgrt_tab.image_address) { + pr_info("efifb: No BGRT, not showing boot graphics\n"); + return; + } + + /* Avoid flashing the logo if we're going to print std probe messages */ + if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) + return; + + /* bgrt_tab.status is unreliable, so we don't check it */ + + if (si->lfb_depth != 32) { + pr_info("efifb: not 32 bits, not showing boot graphics\n"); + return; + } + + bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, + MEMREMAP_WB); + if (!bgrt_image) { + pr_warn("efifb: Ignoring BGRT: failed to map image memory\n"); + return; + } + + if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header))) + goto error; + + file_header = bgrt_image; + if (file_header->id != 0x4d42 || file_header->reserved != 0) + goto error; + + dib_header = bgrt_image + sizeof(*file_header); + if (dib_header->dib_header_size != 40 || dib_header->width < 0 || + dib_header->planes != 1 || dib_header->bpp != 24 || + dib_header->compression != 0) + goto error; + + bmp_width = dib_header->width; + bmp_height = abs(dib_header->height); + bmp_pitch = round_up(3 * bmp_width, 4); + screen_pitch = si->lfb_linelength; + + if ((file_header->bitmap_offset + bmp_pitch * bmp_height) > + bgrt_image_size) + goto error; + + if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width || + (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height) + goto error; + + pr_info("efifb: showing boot graphics\n"); + + for (y = 0; y < si->lfb_height; y++, dst +
[PATCH v2 1/2] efi/bgrt: Drop __initdata from bgrt_image_size
bgrt_image_size is necessary to (optionally) show the boot graphics from the efifb code. The efifb driver is a platform driver, using a normal driver probe() driver callback. So even though it is always builtin it cannot reference __initdata. Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- drivers/firmware/efi/efi-bgrt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 50793fda7819..b22ccfb0c991 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -20,7 +20,7 @@ #include struct acpi_table_bgrt bgrt_tab; -size_t __initdata bgrt_image_size; +size_t bgrt_image_size; struct bmp_header { u16 id; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 0/2] efifb: Copy the ACPI BGRT boot graphics to the
Hi, On 18-06-18 11:23, Daniel Vetter wrote: On Sun, Jun 17, 2018 at 05:32:33PM +0200, Hans de Goede wrote: Hi All, Here is a patch-set to make sure that the efifb contains the boot graphics from the ACPI BGRT extension when the kernel is configured to use the (new) deferred fbcon console takeover support. Let me explain why this is desirable (same reason as for the deferred fbcon console takeover support itself): Various (desktop oriented) Linux distributions have spend a lot of time to not show way too technial boot messages to end users during bootup. What we would really like for the boot experience is something like MacOS X / Windows 10 do. The (EFI) firmware boots up a logo and we leave that in place until the login-manager (e.g. gdm) starts and then the login-manager takes over the framebuffer including the current logo contents and fades that into the login screen. The deferred fbcon console takeover (combined with shim and grub) patches makes the desired boot experience possible, but this assumes that the firmware starts shim with the framebuffer containing the boot graphics. This is not always the case, this patch ensures that the boot graphics are in place. Since the bgrt.status field is not exactly reliable, this commit simply always copies over the bootgraphics. If they are already there this effectively is a no-op. The first patch in this series makes a trivial change to drivers/firmware/efi/efi-bgrt.c, dropping __initdata from bgrt_image_size. Ard, since the second patch depends on the first and the change is really trivial, can we please have your ack for merging the efi-bgrt.c change through the fbdev tree? Random side-comment ... plans to roll out the same for drm drivers? With the client infrastructure Noralf is working on doing that should be fairly straight-forward. Interim step would be to add it to the shared fbdev emulation layer (but that's a bit a hack, and precludes the use of this on fbcon-less systems). I had not really thought about this yet. AFAICT the ACPI BGRT table is part of UEFI, so having it also means having an UEFI framebuffer and I expect us to always use that to be able to show error messages initializing the real drm/kms driver. But I guess in the future the plan it to stop using the efifb linux driver and instead use simple drm, then we will certainly want this in drm. And thinking more about this, currently I'm relying (for a flickerfree experience) on the kms driver taking over the fb setup by the firmware. But I guess it may not always succeed and if it does not succeed, then restoring the bootgraphics (on a quiet boot) would be good too. Once I've everything upstream to make flickerfree work for i915 I plan to look at the amd / nouveau cases next. For those adding BGRT graphics restoration to the drm drivers might make for a good quick fix. We would still get a flicker from the modeset but at least the screen would not be just black until the gui loads if we restore the boot graphics from the drm driver and I guess we could prime the fb with the bootgraphics before the modeset to make the flicker as small as possible. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efifb: Copy the ACPI BGRT boot graphics to the framebuffer
Hi, On 18-06-18 10:43, Ard Biesheuvel wrote: On 18 June 2018 at 10:30, Hans de Goede wrote: Hi, On 18-06-18 09:36, Ard Biesheuvel wrote: Hallo Hans, On 17 June 2018 at 17:32, Hans de Goede wrote: On systems where fbcon is configured for deferred console takeover, the intend is for the framebuffer to show the boot graphics (e.g a vendor logo) until some message (e.g. an error) is printed or a graphical session takes over. Some firmware however relies on the OS to show the boot graphics (indicated by bgrt_tab.status being 0) and the boot graphics may have been destroyed by e.g. the grub boot menu. This patch adds support to efifb to show the boot graphics and automatically enables this when fbcon is configured for deferred console takeover. Signed-off-by: Hans de Goede I have tested this code on ARM QEMU/mach-virt, and with a little tweak (which I will post separately), the code works as expected, i.e., it redraws the boot logo based on the contents of the BGRT table. That is great. However, what it doesn't do is clear the screen, which means the logo is drawn on top of whatever the boot environment left behind, and I end up with something like this. http://people.linaro.org/~ard.biesheuvel/mach-virt-bgrt-logo-redrawn.png Hmm, less great. I'm not sure how to deal with this, on x86 it is more or less guaranteed that the screen is already cleared when we load and clearing a 4k screen means writing about 32MB, which I guess with modern RAM speeds is not that bad actually. I see that you got this picture by manual booting from the EFI shell, in what state does the firmware / bootloader normally leave the framebuffer? UEFI does not usually clear the screen when it boots the default entry, so it is entirely dependent on the boot loader that runs next. I guess GRUB usually clears the screen unconditionally? It depends, GRUB either leaves it completely alone (leaving the BGRT graphics which the firmware hopefully has put up already in place) or if it actually draws anything, then it clears iit before starting the kernel. In any case, I think it is reasonable to clear the screen if you redraw the logo, but I do wonder if it is safe to assume that the background color is black. Instead, we may decide to clear the screen before ExitBootServices() [using EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen()]. On most x86 machines (but not all, GRR) the firmware itself will draw the logo already. I actually have grub patches pending to make it not do any text-output related calls at all unless it actually has a message / menu it wants to display. Calling EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen() will cause a bootup sequence like this: firmware draws logo clearscreen redraw logo Which will cause an ugly flash to black. Where as the purpose is to have a smooth boot with the logo being on screen all the time without any flickers / flashes. I've never seen a machine where the background is not black, the background not being black would also break the spinning dots which microsofts draws on top of the background while booting, so a memset to 0 seems sensible to me. I'm asking because if normally it is either cleared to black, or already showing the logo I wonder if we should take the (small) penalty of clearing ? Given that we are talking about only 32 MB I could do a v2 which just memsets the rest of the screen to 0. So we get: for (y= 0; y < height; y++) { if (line_part_of_bgrt) { memset(left-of-bgrt); draw_bgrt_line(y); memset(right-of-bgrt); } else { memset(line); } } Note I've deliberately done the if on a per line base to keep the actual blit part of the loop efficient and without any extra conditionals in there. I also don't simply first memset the entire fb to 0 to avoid a flash / tearing if the bgrt image is already in place (which happens often on x86). Implementing this is easy and as said the extra execution time should be quite small, still I wonder what others think about this? I'm leaning towards doing the clearing / memsets since I've seen some firmwares leave some artifacts from not completely clearing things like a "Press F2 to enter setup" message, missing a few pixels and leaving those on screen. I think the overhead of doing the clearing is not going to be the bottleneck. But redrawing a logo on black background that was designed to be displayed over another color is going to look really ugly ... Do you know of any examples of this ? There seems to be no known way to get the background color, so black / all 0 seems the be the best bet. I would expect any non black background logos to simply be screen filling. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a me
Re: [PATCH 2/2] efifb: Copy the ACPI BGRT boot graphics to the framebuffer
Hi, On 18-06-18 09:36, Ard Biesheuvel wrote: Hallo Hans, On 17 June 2018 at 17:32, Hans de Goede wrote: On systems where fbcon is configured for deferred console takeover, the intend is for the framebuffer to show the boot graphics (e.g a vendor logo) until some message (e.g. an error) is printed or a graphical session takes over. Some firmware however relies on the OS to show the boot graphics (indicated by bgrt_tab.status being 0) and the boot graphics may have been destroyed by e.g. the grub boot menu. This patch adds support to efifb to show the boot graphics and automatically enables this when fbcon is configured for deferred console takeover. Signed-off-by: Hans de Goede I have tested this code on ARM QEMU/mach-virt, and with a little tweak (which I will post separately), the code works as expected, i.e., it redraws the boot logo based on the contents of the BGRT table. That is great. However, what it doesn't do is clear the screen, which means the logo is drawn on top of whatever the boot environment left behind, and I end up with something like this. http://people.linaro.org/~ard.biesheuvel/mach-virt-bgrt-logo-redrawn.png Hmm, less great. I'm not sure how to deal with this, on x86 it is more or less guaranteed that the screen is already cleared when we load and clearing a 4k screen means writing about 32MB, which I guess with modern RAM speeds is not that bad actually. I see that you got this picture by manual booting from the EFI shell, in what state does the firmware / bootloader normally leave the framebuffer? I'm asking because if normally it is either cleared to black, or already showing the logo I wonder if we should take the (small) penalty of clearing ? Given that we are talking about only 32 MB I could do a v2 which just memsets the rest of the screen to 0. So we get: for (y= 0; y < height; y++) { if (line_part_of_bgrt) { memset(left-of-bgrt); draw_bgrt_line(y); memset(right-of-bgrt); } else { memset(line); } } Note I've deliberately done the if on a per line base to keep the actual blit part of the loop efficient and without any extra conditionals in there. I also don't simply first memset the entire fb to 0 to avoid a flash / tearing if the bgrt image is already in place (which happens often on x86). Implementing this is easy and as said the extra execution time should be quite small, still I wonder what others think about this? I'm leaning towards doing the clearing / memsets since I've seen some firmwares leave some artifacts from not completely clearing things like a "Press F2 to enter setup" message, missing a few pixels and leaving those on screen. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efifb: Copy the ACPI BGRT boot graphics to the framebuffer
Hi, On 18-06-18 10:53, Môshe van der Sterre wrote: Hi Hans, On 06/17/2018 05:32 PM, Hans de Goede wrote: On systems where fbcon is configured for deferred console takeover, the intend is for the framebuffer to show the boot graphics (e.g a vendor logo) until some message (e.g. an error) is printed or a graphical session takes over. Some firmware however relies on the OS to show the boot graphics (indicated by bgrt_tab.status being 0) and the boot graphics may have been destroyed by e.g. the grub boot menu. It may be clearer to just say that the boot graphics may have been destroyed. The reference to the status field and firmware expectations only confuses the intention of this patch, imho. (This ties in to what I say below) This patch adds support to efifb to show the boot graphics and automatically enables this when fbcon is configured for deferred console takeover. + /* +* We do not check bgrt_tab.status here because this seems to only +* reflect if the firmware has shown the boot graphics at all, if it +* later got destroyed by something status will still be 1. +* Since we draw the exact same graphic at the exact same place this +* will not lead to any tearing if the boot graphic is already there. +*/ I agree that ignoring bgrt_tab.status is the absolute best option. The status (valid-bit) can, in the real world, be any value with any meaning. I checked this on a few machines as part of commit 66dbe99cfe30. - My workstation always has 0. - An old server that I checked always has 1. - My laptop has 1 if the boot is uninterrupted, 0 if I request the UEFI boot menu. So, I have the same reservation about this comment as I have about the commit message. Imho, simply mentioning that the status field cannot be relied upon (in any case), would get the point across. Ok, I will simplify both the commit message and comment bits to just state that the status field is unreliable. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 0/2] efifb: Copy the ACPI BGRT boot graphics to the
Hi All, Here is a patch-set to make sure that the efifb contains the boot graphics from the ACPI BGRT extension when the kernel is configured to use the (new) deferred fbcon console takeover support. Let me explain why this is desirable (same reason as for the deferred fbcon console takeover support itself): Various (desktop oriented) Linux distributions have spend a lot of time to not show way too technial boot messages to end users during bootup. What we would really like for the boot experience is something like MacOS X / Windows 10 do. The (EFI) firmware boots up a logo and we leave that in place until the login-manager (e.g. gdm) starts and then the login-manager takes over the framebuffer including the current logo contents and fades that into the login screen. The deferred fbcon console takeover (combined with shim and grub) patches makes the desired boot experience possible, but this assumes that the firmware starts shim with the framebuffer containing the boot graphics. This is not always the case, this patch ensures that the boot graphics are in place. Since the bgrt.status field is not exactly reliable, this commit simply always copies over the bootgraphics. If they are already there this effectively is a no-op. The first patch in this series makes a trivial change to drivers/firmware/efi/efi-bgrt.c, dropping __initdata from bgrt_image_size. Ard, since the second patch depends on the first and the change is really trivial, can we please have your ack for merging the efi-bgrt.c change through the fbdev tree? Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 1/2] efi/bgrt: Drop __initdata from bgrt_image_size
bgrt_image_size is necessary to (optionally) show the boot graphics from the efifb code. The efifb driver is a platform driver, using a normal driver probe() driver callback. So even though it is always builtin it cannot reference __initdata. Signed-off-by: Hans de Goede --- drivers/firmware/efi/efi-bgrt.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/drivers/firmware/efi/efi-bgrt.c b/drivers/firmware/efi/efi-bgrt.c index 50793fda7819..b22ccfb0c991 100644 --- a/drivers/firmware/efi/efi-bgrt.c +++ b/drivers/firmware/efi/efi-bgrt.c @@ -20,7 +20,7 @@ #include struct acpi_table_bgrt bgrt_tab; -size_t __initdata bgrt_image_size; +size_t bgrt_image_size; struct bmp_header { u16 id; -- 2.17.1 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] efifb: Copy the ACPI BGRT boot graphics to the framebuffer
On systems where fbcon is configured for deferred console takeover, the intend is for the framebuffer to show the boot graphics (e.g a vendor logo) until some message (e.g. an error) is printed or a graphical session takes over. Some firmware however relies on the OS to show the boot graphics (indicated by bgrt_tab.status being 0) and the boot graphics may have been destroyed by e.g. the grub boot menu. This patch adds support to efifb to show the boot graphics and automatically enables this when fbcon is configured for deferred console takeover. Signed-off-by: Hans de Goede --- drivers/video/fbdev/efifb.c | 147 1 file changed, 147 insertions(+) diff --git a/drivers/video/fbdev/efifb.c b/drivers/video/fbdev/efifb.c index 46a4484e3da7..b041d936a438 100644 --- a/drivers/video/fbdev/efifb.c +++ b/drivers/video/fbdev/efifb.c @@ -9,16 +9,39 @@ #include #include +#include #include #include #include #include +#include #include #include #include #include /* For drm_get_panel_orientation_quirk */ #include /* For DRM_MODE_PANEL_ORIENTATION_* */ +struct bmp_file_header { + u16 id; + u32 file_size; + u32 reserved; + u32 bitmap_offset; +} __packed; + +struct bmp_dib_header { + u32 dib_header_size; + s32 width; + s32 height; + u16 planes; + u16 bpp; + u32 compression; + u32 bitmap_size; + u32 horz_resolution; + u32 vert_resolution; + u32 colors_used; + u32 colors_important; +} __packed; + static bool request_mem_succeeded = false; static bool nowc = false; @@ -66,6 +89,128 @@ static int efifb_setcolreg(unsigned regno, unsigned red, unsigned green, return 0; } +/* + * If fbcon deffered console takeover is configured, the intent is for the + * framebuffer to show the boot graphics (e.g. vendor logo) until there is some + * (error) message to display. But the boot graphics may have been destroyed by + * e.g. option ROM output, detect this and restore the boot graphics. + */ +#if defined CONFIG_FRAMEBUFFER_CONSOLE_DEFERRED_TAKEOVER && \ +defined CONFIG_ACPI_BGRT +static void efifb_show_boot_graphics(struct fb_info *info) +{ + u32 *dst, bmp_width, bmp_height, bmp_pitch, screen_pitch; + struct screen_info *si = &screen_info; + struct bmp_file_header *file_header; + struct bmp_dib_header *dib_header; + void *bgrt_image = NULL; + u8 *src, r, g, b; + s32 x, y; + + if (!bgrt_tab.image_address) { + pr_info("efifb: No BGRT, not showing boot graphics\n"); + return; + } + + /* Avoid flashing the logo if we're going to print std probe messages */ + if (console_loglevel > CONSOLE_LOGLEVEL_QUIET) + return; + + /* +* We do not check bgrt_tab.status here because this seems to only +* reflect if the firmware has shown the boot graphics at all, if it +* later got destroyed by something status will still be 1. +* Since we draw the exact same graphic at the exact same place this +* will not lead to any tearing if the boot graphic is already there. +*/ + + if (si->lfb_depth != 32) { + pr_info("efifb: not 32 bits, not showing boot graphics\n"); + return; + } + + bgrt_image = memremap(bgrt_tab.image_address, bgrt_image_size, + MEMREMAP_WB); + if (!bgrt_image) { + pr_warn("efifb: Ignoring BGRT: failed to map image memory\n"); + return; + } + + if (bgrt_image_size < (sizeof(*file_header) + sizeof(*dib_header))) + goto error; + + file_header = bgrt_image; + if (file_header->id != 0x4d42 || file_header->reserved != 0) + goto error; + + dib_header = bgrt_image + sizeof(*file_header); + if (dib_header->dib_header_size != 40 || dib_header->width < 0 || + dib_header->planes != 1 || dib_header->bpp != 24 || + dib_header->compression != 0) + goto error; + + bmp_width = dib_header->width; + bmp_height = abs(dib_header->height); + bmp_pitch = round_up(3 * bmp_width, 4); + screen_pitch = si->lfb_linelength; + + if ((file_header->bitmap_offset + bmp_pitch * bmp_height) > + bgrt_image_size) + goto error; + + if ((bgrt_tab.image_offset_x + bmp_width) > si->lfb_width || + (bgrt_tab.image_offset_y + bmp_height) > si->lfb_height) + goto error; + + pr_info("efifb: showing boot graphics\n"); + + src = bgrt_image + file_header->bitmap_offset; + bmp_pitch -= 3 * bmp_width; + if (dib_header->height < 0) { + for (y = 0; y < bmp_height; y++) { +
Re: [PATCH v6 2/5] efi: Add embedded peripheral firmware support
Hi, On 06-06-18 23:42, Luis R. Rodriguez wrote: On Wed, Jun 06, 2018 at 08:39:15PM +0200, Hans de Goede wrote: On 05-06-18 23:07, Luis R. Rodriguez wrote: +To make request_firmware() fallback to trying EFI embedded firmwares after this, +the driver must set a boolean "efi-embedded-firmware" device-property on the +device before passing it to request_firmware(). No, as I have requested before I don't want this, it is silly to have such functionality always be considered as a fallback if we only have 2 drivers which need this. > Please add a call which only if used would then *evaluate* such fallback prospect. Ok, so I've a few questions about this: 1) You want me to add a: int firmware_request_with_system_firmware_fallback(struct device *device, const char *name); function? The idea is correct, the name however is obviously terrible. This is functionality that is very specialized and only *two* device drivers need it that we are aware of which would be upstream. Experience has shown fallback mechanisms *can* be a pain, and if we add this we will be supporting this for *life*, as such I'd very much prefer to: a) *Clearly* reduce the scope of functionality clearly *beyond* what you have done. b) Have access to one simple call which folks can use to *clearly* and quickly grep for those oddball drivers using this new interface. We can do this by using a separate function for it. Before you claim something seems unreasonable from the above logic, please read the latest state of affairs with respect to data driven Vs functional API evolution discussion over the firmware API [0] as well as my latests recommendation for what to do for the async firmware API [1]. The skinny of it is that long ago I actually proposed having only *two* firmware API calls, an async and a sync call and having all functionality fleshed out through a structure of parameters. The issue with that strategy was it was *too* data driven, and as per Greg's request we'll instead be exposing new symbols per functionality for the firmware API with his justification that this is just what is traditionally done on Linux. Hence we have firmware_request_nowarn() now for just a slight variation for a sync call. Despite Greg's recommendation -- for the respective async functionality I suggested this is not going to scale well -- it is also just dumb to follow the same approach there for a few reasons. 1) We have only *one* async call and had decided to *not* provide a structure for that call since its inception 2) Over time have evolved this single async call each time we have a new feature, causing a slew of collateral evolutions. So, while we like it or not, it turns out the async call to the firmware API is already completely data driven. Extending it with just another argument would just be silly now. So refer to my recommendations to Andres for how to evolve the async API if you need it, however from a quick review you don't need async calls, so you won't have to address any of that. [0] https://lkml.kernel.org/r/20180421173650.gw14...@wotan.suse.de [1] https://lkml.kernel.org/r/20180422202609.gx14...@wotan.suse.de Note I've deliberately named it with_system_firmware_fallback and not with_efi_fallback to have the name be platform agnostic in case we want something similar on other platforms in the future. firmware_request_platform() ? And then have this pass a new FW_OPT_SYS_FW_FALLBACK flag to _request_firmware(), right ? Yeap. 2) Should this flag then be checked inside _request_firmware() before it calls fw_get_efi_embedded_fw() (which may be an empty stub), You are the architect behind this call, so its up to you. To answer this you have to review the other flags and see if other users of the other flags may want your functionality. For instance the Android folks for instance rely on the FW_OPT_NOFALLBACK - the sysfs fallback mechanism to account for odd partition layouts. Could they ever want to use your fallback mechanism? Granted your mechanism is for x86, but they could eventually add support for it on ARM. Checking if the firmware is on the EFI platform firmware list is much faster than the fallback mechanism, that would be one gain for them, as such it may make sense to check for firmware_request_platform() before using the sysfs fallback mechanism. However if Android folks want to always override the platform firmware with the sysfs fallback interface we'd need another flag added and call to then change the order later if we checked for for the platform firmware first. I believe we agreed a while back that the platform fallback would replace the sysfs one when requested. I believe that still makes sense. If a driver wants both it can simply call request_firmware_foo itself twice and determine the order itself. If you however are 100% sure they won't need it, than checking firmware_request_platform() first w
Re: [PATCH v6 2/5] efi: Add embedded peripheral firmware support
Hi, On 05-06-18 23:07, Luis R. Rodriguez wrote: On Fri, Jun 01, 2018 at 02:53:27PM +0200, Hans de Goede wrote: Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v6: -Rework code to remove casts from if (prefix == mem) comparison -Use SHA256 hashes instead of crc32 sums -Add new READING_FIRMWARE_EFI_EMBEDDED read_file_id and use it -Call security_kernel_read_file(NULL, READING_FIRMWARE_EFI_EMBEDDED) to check if this is allowed before looking at EFI embedded fw -Document why we are not using the PI Firmware Volume protocol Changes in v5: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS Changes in v4: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set --- .../driver-api/firmware/request_firmware.rst | 76 + drivers/base/firmware_loader/Makefile | 1 + drivers/base/firmware_loader/fallback.h | 12 ++ drivers/base/firmware_loader/fallback_efi.c | 56 +++ drivers/base/firmware_loader/main.c | 2 + drivers/firmware/efi/Kconfig | 3 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 148 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ include/linux/fs.h| 1 + init/mai
Re: [PATCH v6 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi, On 05-06-18 22:46, Luis R. Rodriguez wrote: On Fri, Jun 01, 2018 at 02:53:25PM +0200, Hans de Goede wrote: Hi All, Here is v6 of my patch-set to add support for EFI embedded fw to the kernel. This patch-set applies on top of the "[PATCH v7 00/14] firmware_loader changes for v4.18" series from mcgrof. It now also depends on the series from Andy Lutomirski which allow using the sha256 code in a standalone manner. Andy what is the status of those? Changes since v5: -Rework code to remove casts from if (prefix == mem) comparison -Use SHA256 hashes instead of crc32 sums Nice! I see no updates on this progress, but it would seem this may then mean this cannot be merged until the release after? Once the sha256 bits are in place the subsys tree which has them merged can create an immutable branch for Greg to merge and then these can be applied on top of that merge. But yes this means that these probably won't go in for another cycle or 2, that is fine. -Add new READING_FIRMWARE_EFI_EMBEDDED read_file_id and use it -Call security_kernel_read_file(NULL, READING_FIRMWARE_EFI_EMBEDDED) to check if this is allowed before looking at EFI embedded fw There's a discussion over having security_kernel_read_file(NULL, READING_WHATEVER) become another LSM hook. So your series would conflict with that at the moment. So yet another piece of code which this series depends on. Ah well, I'm in no big hurry to get this merged. OTOH if this is ready and that discussion is not yet finished it might be better to merge this as is and then have the security_kernel_read_file / LSM hook series fix this up as necessary when it is merged. Regards, Hans -Document why we are not using the PI Firmware Volume protocol For reference I've included the coverletter from v4 (which includes previous covverletters) below. Regards, Hans Previous coverletter: Here is v5 of my patch-set to add support for EFI embedded fw to the kernel. Changes since v4: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS So I think this patch-set is getting close to ready for merging, which brings us to the question of how to merge this, I think that patches 1 and 2 should probably both be merged through the same tree. Then an unmutable branch should be created on that tree, merged into the platform/x86 tree and then the last 3 patches can be merged through that tree. Ard has already indicated he is fine with the EFI bits going upstream through another tree, so perhaps patches 1-2 can be merged through the firmware-loader-tree and then do an unmutable branch on the firmware-loader-tree for the platform/x86 tree to merge? I don't think taking all 5 through 1 tree is a good idea because of the file rename under platform/x86. For the record here are the cover letters of the previous versions: Changes since v3: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it The 3 most prominent changes in v2 are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-firmware" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-
[PATCH v6 3/5] platform/x86: Rename silead_dmi to touchscreen_dmi
Not only silead touchscreens need some extra info not available in the ACPI tables to work properly. X86 devices with a Chipone ICN8505 chip also need some DMI based extra configuration. There is no reason to have separate dmi config code per touchscreen controller vendor. This commit renames silead_dmi to a more generic touchscreen_dmi name (and Kconfig option) in preparation of adding info for tablets with an ICN8505 based touchscreen. Note there are no functional changes all code changes are limited to removing references to silead where these are no longer applicable. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- drivers/platform/x86/Kconfig | 16 ++--- drivers/platform/x86/Makefile | 2 +- .../x86/{silead_dmi.c => touchscreen_dmi.c} | 72 +-- 4 files changed, 46 insertions(+), 46 deletions(-) rename drivers/platform/x86/{silead_dmi.c => touchscreen_dmi.c} (88%) diff --git a/MAINTAINERS b/MAINTAINERS index 9474e9834dc7..6b02f2b9814d 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12775,7 +12775,7 @@ L: linux-in...@vger.kernel.org L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/input/touchscreen/silead.c -F: drivers/platform/x86/silead_dmi.c +F: drivers/platform/x86/touchscreen_dmi.c SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 566644bb496a..d4e9670ee8cc 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..8d9477114fb5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI)+= alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC)+= intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c similarity index 88% rename from drivers/platform/x86/silead_dmi.c rename to drivers/platform/x86/touchscreen_dmi.c index 853a7ce4601c..8fb489e1e16c 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,7 +20,7 @@ #include #include -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; @@ -34,7 +34,7 @@ static const struct property_entry cube_iwork8_air_props[] = { { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -48,7 +48,7 @@ static const struct property_entry jumper_ezpad_mini3_props[] = { { } }; -static const struct silead_ts
[PATCH v6 1/5] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Reviewed-by: Greg Kroah-Hartman Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v5: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS Changes in v4: -Add new EFI_BOOT_SERVICES flag and use it to determine if the boot-services memory segments are available (and thus if it makes sense to register the debugfs bits for them) Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/efi.c| 1 + arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ include/linux/efi.h| 1 + 4 files changed, 59 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 9061babfbc83..82f0836d 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -208,6 +208,7 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_version); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); + set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags); return 0; } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..16bdb9e3b343 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -376,6 +376,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 232f4915223b..1590e4d6a857 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -325,6 +326,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -369,6 +419,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS)) + efi_debugfs_init(); + return 0; err_remove_group: diff --git a/include/linux/efi.h b/include/linux/efi.h index 56add823f190..d72358e892e7 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1144,6 +1144,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_DBG8 /* Print additional debug info at runtime */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ #define EFI_MEM_ATTR 10 /* Did firmware publish
[PATCH v6 2/5] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v6: -Rework code to remove casts from if (prefix == mem) comparison -Use SHA256 hashes instead of crc32 sums -Add new READING_FIRMWARE_EFI_EMBEDDED read_file_id and use it -Call security_kernel_read_file(NULL, READING_FIRMWARE_EFI_EMBEDDED) to check if this is allowed before looking at EFI embedded fw -Document why we are not using the PI Firmware Volume protocol Changes in v5: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS Changes in v4: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set --- .../driver-api/firmware/request_firmware.rst | 76 + drivers/base/firmware_loader/Makefile | 1 + drivers/base/firmware_loader/fallback.h | 12 ++ drivers/base/firmware_loader/fallback_efi.c | 56 +++ drivers/base/firmware_loader/main.c | 2 + drivers/firmware/efi/Kconfig | 3 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 148 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ include/linux/fs.h| 1 + init/main.c | 3 + 12 files changed, 334 insertions(+) create mode 100644 drivers/base/firmware_loader/fallback_efi.c
[PATCH v6 5/5] platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
Add touchscreen info for the Chuwi Vi8 Plus tablet. This tablet uses a Chipone ICN8505 touchscreen controller, with the firmware used by the touchscreen embedded in the EFI firmware. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v6: -Switch from crc sums to SHA256 hashes for the firmware hash --- drivers/platform/x86/touchscreen_dmi.c | 28 ++ 1 file changed, 28 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 8eb88bfcacbe..99eb73bbd1a0 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -359,6 +359,25 @@ static const struct ts_dmi_data onda_v891w_v1_data = { .properties = onda_v891w_v1_props, }; +static const struct property_entry efi_embedded_fw_props[] = { + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), + { } +}; + +static const struct ts_dmi_data chuwi_vi8_plus_data = { + .embedded_fw = { + .name = "chipone/icn8505-HAMP0002.fw", + .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 }, + .length = 35012, + .sha256 = { 0x93, 0xe5, 0x49, 0xe0, 0xb6, 0xa2, 0xb4, 0xb3, + 0x88, 0x96, 0x34, 0x97, 0x5e, 0xa8, 0x13, 0x78, + 0x72, 0x98, 0xb8, 0x29, 0xeb, 0x5c, 0xa7, 0xf1, + 0x25, 0x13, 0x43, 0xf4, 0x30, 0x7c, 0xfc, 0x7c }, + }, + .acpi_name = "CHPN0001:00", + .properties = efi_embedded_fw_props, +}; + const struct dmi_system_id touchscreen_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -587,6 +606,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_EXACT_MATCH(DMI_BIOS_VERSION, "ONDA.W89EBBN08"), }, }, + { + /* Chuwi Vi8 Plus (CWI506) */ + .driver_data = (void *)&chuwi_vi8_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, { }, }; -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v6 4/5] platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
Sofar we have been unable to get permission from the vendors to put the firmware for touchscreens listed in touchscreen_dmi in linux-firmware. Some of the tablets with such a touchscreen have a touchscreen driver, and thus a copy of the firmware, as part of their EFI code. This commit adds the necessary info for the new EFI embedded-firmware code to extract these firmwares, making the touchscreen work OOTB without the user needing to manually add the firmware. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v6: -Switch from crc sums to SHA256 hashes for the firmware hashes --- drivers/firmware/efi/embedded-firmware.c | 3 ++ drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/touchscreen_dmi.c | 35 +++- include/linux/efi_embedded_fw.h | 2 ++ 4 files changed, 40 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index 244465a162c5..19168b83cd06 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -23,6 +23,9 @@ struct embedded_fw { static LIST_HEAD(found_fw_list); static const struct dmi_system_id * const embedded_fw_table[] = { +#ifdef CONFIG_TOUCHSCREEN_DMI + touchscreen_dmi_table, +#endif NULL }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index d4e9670ee8cc..8c2082c8a7fd 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1199,6 +1199,7 @@ config INTEL_TURBO_MAX_3 config TOUCHSCREEN_DMI bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD + select EFI_EMBEDDED_FIRMWARE if EFI ---help--- Certain ACPI based tablets with e.g. Silead or Chipone touchscreens do not have enough data in ACPI tables for the touchscreen driver to diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 8fb489e1e16c..8eb88bfcacbe 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include #include struct ts_dmi_data { + /* The EFI embedded-fw code expects this to be the first member! */ + struct efi_embedded_fw_desc embedded_fw; const char *acpi_name; const struct property_entry *properties; }; @@ -31,10 +34,20 @@ static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data cube_iwork8_air_data = { + .embedded_fw = { + .name = "silead/gsl3670-cube-iwork8-air.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 38808, + .sha256 = { 0xff, 0x62, 0x2d, 0xd1, 0x8a, 0x78, 0x04, 0x7b, + 0x33, 0x06, 0xb0, 0x4f, 0x7f, 0x02, 0x08, 0x9c, + 0x96, 0xd4, 0x9f, 0x04, 0xe1, 0x47, 0x25, 0x25, + 0x60, 0x77, 0x41, 0x33, 0xeb, 0x12, 0x82, 0xfc }, + }, .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -133,10 +146,20 @@ static const struct property_entry pipo_w2s_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data pipo_w2s_data = { + .embedded_fw = { + .name = "silead/gsl1680-pipo-w2s.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39072, + .sha256 = { 0xd0, 0x58, 0xc4, 0x7d, 0x55, 0x2d, 0x62, 0x18, + 0xd1, 0x6a, 0x71, 0x73, 0x0b, 0x3f, 0xbe, 0x60, + 0xbb, 0x45, 0x8c, 0x52, 0x27, 0xb7, 0x18, 0xf4, + 0x31, 0x00, 0x6a, 0x49, 0x76, 0xd8, 0x7c, 0xd3 }, + }, .acpi_name = "MSSL1680:00", .properties = pipo_w2s_props, }; @@ -194,10 +217,20 @@ static const struct property_entry chuwi_hi8_pro_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), PROPERTY_ENTRY_BOOL("silead,home-button"), +
[PATCH v6 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi All, Here is v6 of my patch-set to add support for EFI embedded fw to the kernel. This patch-set applies on top of the "[PATCH v7 00/14] firmware_loader changes for v4.18" series from mcgrof. It now also depends on the series from Andy Lutomirski which allow using the sha256 code in a standalone manner. Andy what is the status of those? Changes since v5: -Rework code to remove casts from if (prefix == mem) comparison -Use SHA256 hashes instead of crc32 sums -Add new READING_FIRMWARE_EFI_EMBEDDED read_file_id and use it -Call security_kernel_read_file(NULL, READING_FIRMWARE_EFI_EMBEDDED) to check if this is allowed before looking at EFI embedded fw -Document why we are not using the PI Firmware Volume protocol For reference I've included the coverletter from v4 (which includes previous covverletters) below. Regards, Hans Previous coverletter: Here is v5 of my patch-set to add support for EFI embedded fw to the kernel. Changes since v4: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS So I think this patch-set is getting close to ready for merging, which brings us to the question of how to merge this, I think that patches 1 and 2 should probably both be merged through the same tree. Then an unmutable branch should be created on that tree, merged into the platform/x86 tree and then the last 3 patches can be merged through that tree. Ard has already indicated he is fine with the EFI bits going upstream through another tree, so perhaps patches 1-2 can be merged through the firmware-loader-tree and then do an unmutable branch on the firmware-loader-tree for the platform/x86 tree to merge? I don't think taking all 5 through 1 tree is a good idea because of the file rename under platform/x86. For the record here are the cover letters of the previous versions: Changes since v3: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it The 3 most prominent changes in v2 are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-firmware" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Patches 3-5 are new and implement using the EFI
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/08/2018 06:12 PM, Luis R. Rodriguez wrote: On Fri, May 04, 2018 at 07:54:28AM +0200, Ard Biesheuvel wrote: On 4 May 2018 at 01:29, Luis R. Rodriguez wrote: On Sun, Apr 29, 2018 at 11:35:55AM +0200, Hans de Goede wrote: [...] diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index c8bddbdcfd10..560dfed76e38 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -73,3 +73,69 @@ If something went wrong firmware_request() returns non-zero and fw_entry is set to NULL. Once your driver is done with processing the firmware it can call call firmware_release(fw_entry) to release the firmware image and any related resource. + +EFI embedded firmware support += This is a new fallback mechanism, please see: Documentation/driver-api/firmware/fallback-mechanisms.rst Refer to the section "Types of fallback mechanisms", augument the list there and then move the section "Firmware sysfs loading facility" to a new file, and then add a new file for your own. + +On some devices the system's EFI code / ROM may contain an embedded copy +of firmware for some of the system's integrated peripheral devices and +the peripheral's Linux device-driver needs to access this firmware. You in no way indicate this is a just an invented scheme, a custom solution and nothing standard. I realize Ard criticized that the EFI Firmware Volume Protocol is not part of the UEFI spec -- however it is a bit more widely used right? Why can't Linux support it instead? Most implementations of UEFI are based on PI, That seems to be the UEFI Platform Initialization specification: http://www.uefi.org/sites/default/files/resources/PI_Spec_1_6.pdf and so it is likely that the protocols are available. However, the PI spec does not cover firmware blobs, Indeed, I cannot find anything about it on the PI Spec, but I *can* easily find a few documents referring to the Firmware Volume Protocol: http://wiki.phoenix.com/wiki/index.php/EFI_FIRMWARE_VOLUME_PROTOCOL But this has no references at all... I see stupid patents over some of this and authentication mechanisms for it: https://patents.google.com/patent/US20170098084 and so it is undefined whether such blobs are self contained (i.e., in separate files in the firmware volume), statically linked into the driver or maybe even encrypted or otherwise encapsulated, and the actual loadable image only lives in memory. Got it, thanks this helps! There are two things then: 1) The "EFI Firmware Volume Protocol" ("FV" for short in your descriptions below), and whether to support it or not in the future and recommend it for future use cases. b) Han's EFI scraper to help support 2 drivers, and whether or not to recommend it for future use cases. Hans's case is the second one, i.e., the firmware is at an arbitrary offset in the driver image. Using the FV protocol in this case would result in a mix of both approaches: look up the driver file by GUID [which could change btw between different versions of the system firmware, although this is unlikely] and then still use the prefix/crc based approach to sift through the image itself. Got it. And to be clear its a reversed engineered solution to what two vendors decided to do. But my main objection is simply that from the UEFI forum point of view, there is a clear distinction between the OS visible interfaces in the UEFI spec and the internal interfaces in the PI spec (which for instance are not subject to the same rules when it comes to backward compatibility), and so I think we should not depend on PI at all. Ah I see. This is all the more important considering that we are trying to encourage the creation of other implementations of UEFI that are not based on PI (e.g., uboot for arm64 implements the required UEFI interfaces for booting the kernel via GRUB), and adding dependencies on PI protocols makes that a moving target. Got it! So in my view, we either take a ad-hoc approach which works for the few platforms we expect to support, in which case Hans's approach is sufficient, Modulo it needs some work for ARM as it only works for x86 right now ;) or we architect it properly, in which case we shouldn't depend on PI because it does not belong in a properly architected OS<->firmware exchange. OK, it sounds to me like we have room to then implement our own de-facto standard for letting vendors stuff firmware into EFI as we in the Linux community see fit. We can start out by supporting existing drivers, but also consider customizing this in the future for our own needs, so long as we document it and set expectations well. So we need to support what Hans is implementing for two reasons then: a) The FV Protocol cannot be used to
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/13/2018 12:43 PM, Ard Biesheuvel wrote: On 13 May 2018 at 13:03, Hans de Goede wrote: Hi, On 05/04/2018 06:56 AM, Ard Biesheuvel wrote: Hi Hans, One comment below, which I missed in review before. On 29 April 2018 at 11:35, Hans de Goede wrote: Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- [...] diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c new file mode 100644 index ..22a0f598b53d --- /dev/null +++ b/drivers/firmware/efi/embedded-firmware.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for extracting embedded firmware for peripherals from EFI code, + * + * Copyright (c) 2018 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include + +struct embedded_fw { + struct list_head list; + const char *name; + void *data; + size_t length; +}; + +static LIST_HEAD(found_fw_list); + +static const struct dmi_system_id * const embedded_fw_table[] = { + NULL +}; + +/* + * Note the efi_check_for_embedded_firmwares() code currently makes the + * following 2 assumptions. This may needs to be revisited if embedded firmware + * is found where this is not true: + * 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments + * 2) The firmware always starts at an offset which is a multiple of 8 bytes + */ +static int __init efi_check_md_for_embedded_firmware( + efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc) +{ + struct embedded_fw *fw; + u64 i, size; + u32 crc; + u8 *mem; + + size = md->num_pages << EFI_PAGE_SHIFT; + mem = memremap(md->phys_addr, size, MEMREMAP_WB); + if (!mem) { + pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr); + return -ENOMEM; + } + + size -= desc->length; + for (i = 0; i < size; i += 8) { + if (*((u64 *)(mem + i)) != *((u64 *)desc->prefix)) + continue; + Please use the proper APIs here to cast u8* to u64*, i.e., either use get_unaligned64() or use memcmp() But we know the memory addresses are 64 bit aligned, so using get_unaligned64 seems wrong, and I'm not sure if the compiler is smart enough to optimize a memcmp to the single 64 bit integer comparison we want done here. Fair enough. The memory regions are indeed guaranteed to be 4k aligned. So in that case, please make mem a u64* and cast the other way where needed. Ok, I've reworked the code to get rid of the compares in the if condition. Regards, Hans + /* Seed with ~0, invert to match crc32 userspace utility */ + crc = ~crc32(~0, mem + i, desc->length); + if (crc == desc->crc) + break; + } + + memunmap(mem); + + if (i >= size) + return -ENOENT; + + pr_info("Found EFI embedded fw '%s' crc %08x\n", desc->name, desc->crc); + + fw = kmalloc(sizeof(*fw), GFP_KERNEL); + if (!fw) + return -ENOMEM; + +
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/03/2018 11:35 PM, Andy Lutomirski wrote: On Thu, May 3, 2018 at 3:31 PM Luis R. Rodriguez wrote: On Wed, May 02, 2018 at 04:49:53PM +0200, Hans de Goede wrote: Hi, On 05/01/2018 09:29 PM, Andy Lutomirski wrote: On Sun, Apr 29, 2018 at 2:36 AM Hans de Goede wrote: +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if the prefix is found it +then does a crc32 over length bytes and if that matches makes a copy of length +bytes and adds that to its list with found firmwares. + Eww, gross. Is there really no better way to do this? I'm afraid not. Is the issue that the EFI code does not intend to pass the firmware to the OS but that it has a copy for its own purposes and that Linux is just going to hijack EFI's copy? If so, that's brilliant and terrible at the same time. Yes that is exactly the issue / what it happening here. + for (i = 0; i < size; i += 8) { + if (*((u64 *)(mem + i)) != *((u64 *)desc->prefix)) + continue; + + /* Seed with ~0, invert to match crc32 userspace utility */ + crc = ~crc32(~0, mem + i, desc->length); + if (crc == desc->crc) + break; + } I hate to play the security card, but this stinks a bit. The kernel obviously needs to trust the EFI boot services code since the EFI boot services code is free to modify the kernel image. But your patch is not actually getting this firmware blob from the boot services code via any defined interface -- you're literally snarfing up the blob from a range of memory. I fully expect there to be any number of ways for untrustworthy entities to inject malicious blobs into this memory range on quite a few implementations. For example, there are probably unauthenticated EFI variables and even parts of USB sticks and such that get read into boot services memory, and I see no reason at all to expect that nothing in the so-called "boot services code" range is actually just plain old boot services *heap*. Fortunately, given your design, this is very easy to fix. Just replace CRC32 with SHA-256 or similar. If you find the crypto api too ugly for this purpose, I have patches that only need a small amount of dusting off to give an entirely reasonable SHA-256 API in the kernel. My main reason for going with crc32 is that the scanning happens before the kernel is fully up and running (it happens just before the rest_init() call in start_kernel() (from init/main.c) I'm open to using the crypto api, but I was not sure if that is ready for use at that time. Not being sure is different than being certain. As Andy noted, if that does not work please poke Andy about the SHA-256 API he has which would enable its use in kernel. Nah, don't use the cryptoapi for this. You'll probably regret it for any number of reasons. My code is here: https://git.kernel.org/pub/scm/linux/kernel/git/luto/linux.git/commit/?h=crypto/sha256_bpf&id=e9e12f056f2abed50a30b762db9185799f5864e6 and its two parents. It needs a little bit of dusting and it needs checking that all combinations of modular and non-modular builds work. Ard probably has further comments. Looks good, I've cherry picked this into my personal tree and will make the next version of the EFI embedded-firmware patches use SHA256. As Luis already mentioned geting the EFI embedded-firmware patches upstream is not something urgent, so it is probably best to just wait for you to push these upstream I guess? Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/03/2018 11:31 PM, Luis R. Rodriguez wrote: On Wed, May 02, 2018 at 04:49:53PM +0200, Hans de Goede wrote: Hi, On 05/01/2018 09:29 PM, Andy Lutomirski wrote: On Sun, Apr 29, 2018 at 2:36 AM Hans de Goede wrote: +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if the prefix is found it +then does a crc32 over length bytes and if that matches makes a copy of length +bytes and adds that to its list with found firmwares. + Eww, gross. Is there really no better way to do this? I'm afraid not. Is the issue that the EFI code does not intend to pass the firmware to the OS but that it has a copy for its own purposes and that Linux is just going to hijack EFI's copy? If so, that's brilliant and terrible at the same time. Yes that is exactly the issue / what it happening here. + for (i = 0; i < size; i += 8) { + if (*((u64 *)(mem + i)) != *((u64 *)desc->prefix)) + continue; + + /* Seed with ~0, invert to match crc32 userspace utility */ + crc = ~crc32(~0, mem + i, desc->length); + if (crc == desc->crc) + break; + } I hate to play the security card, but this stinks a bit. The kernel obviously needs to trust the EFI boot services code since the EFI boot services code is free to modify the kernel image. But your patch is not actually getting this firmware blob from the boot services code via any defined interface -- you're literally snarfing up the blob from a range of memory. I fully expect there to be any number of ways for untrustworthy entities to inject malicious blobs into this memory range on quite a few implementations. For example, there are probably unauthenticated EFI variables and even parts of USB sticks and such that get read into boot services memory, and I see no reason at all to expect that nothing in the so-called "boot services code" range is actually just plain old boot services *heap*. Fortunately, given your design, this is very easy to fix. Just replace CRC32 with SHA-256 or similar. If you find the crypto api too ugly for this purpose, I have patches that only need a small amount of dusting off to give an entirely reasonable SHA-256 API in the kernel. My main reason for going with crc32 is that the scanning happens before the kernel is fully up and running (it happens just before the rest_init() call in start_kernel() (from init/main.c) I'm open to using the crypto api, but I was not sure if that is ready for use at that time. Not being sure is different than being certain. As Andy noted, if that does not work please poke Andy about the SHA-256 API he has which would enable its use in kernel. Right now this is just a crazy hack for *2* drivers. Its a lot of hacks for just that, so no need to rush this in just yet. I agree that there is no rush to get this in. I will rebase this on top of the "[PATCH v7 00/14] firmware_loader changes for v4.18" series you recently send as well as try to address all the remarks made sofar. I'm not entirely sure when I will get around to this. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/04/2018 06:56 AM, Ard Biesheuvel wrote: Hi Hans, One comment below, which I missed in review before. On 29 April 2018 at 11:35, Hans de Goede wrote: Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- [...] diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c new file mode 100644 index ..22a0f598b53d --- /dev/null +++ b/drivers/firmware/efi/embedded-firmware.c @@ -0,0 +1,149 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Support for extracting embedded firmware for peripherals from EFI code, + * + * Copyright (c) 2018 Hans de Goede + */ + +#include +#include +#include +#include +#include +#include +#include + +struct embedded_fw { + struct list_head list; + const char *name; + void *data; + size_t length; +}; + +static LIST_HEAD(found_fw_list); + +static const struct dmi_system_id * const embedded_fw_table[] = { + NULL +}; + +/* + * Note the efi_check_for_embedded_firmwares() code currently makes the + * following 2 assumptions. This may needs to be revisited if embedded firmware + * is found where this is not true: + * 1) The firmware is only found in EFI_BOOT_SERVICES_CODE memory segments + * 2) The firmware always starts at an offset which is a multiple of 8 bytes + */ +static int __init efi_check_md_for_embedded_firmware( + efi_memory_desc_t *md, const struct efi_embedded_fw_desc *desc) +{ + struct embedded_fw *fw; + u64 i, size; + u32 crc; + u8 *mem; + + size = md->num_pages << EFI_PAGE_SHIFT; + mem = memremap(md->phys_addr, size, MEMREMAP_WB); + if (!mem) { + pr_err("Error mapping EFI mem at %#llx\n", md->phys_addr); + return -ENOMEM; + } + + size -= desc->length; + for (i = 0; i < size; i += 8) { + if (*((u64 *)(mem + i)) != *((u64 *)desc->prefix)) + continue; + Please use the proper APIs here to cast u8* to u64*, i.e., either use get_unaligned64() or use memcmp() But we know the memory addresses are 64 bit aligned, so using get_unaligned64 seems wrong, and I'm not sure if the compiler is smart enough to optimize a memcmp to the single 64 bit integer comparison we want done here. Regards, Hans + /* Seed with ~0, invert to match crc32 userspace utility */ + crc = ~crc32(~0, mem + i, desc->length); + if (crc == desc->crc) + break; + } + + memunmap(mem); + + if (i >= size) + return -ENOENT; + + pr_info("Found EFI embedded fw '%s' crc %08x\n", desc->name, desc->crc); + + fw = kmalloc(sizeof(*fw), GFP_KERNEL); + if (!fw) + return -ENOMEM; + + mem = memremap(md->phys_addr + i, desc->length, MEMREMAP_WB); + if (!mem) { + pr_err("Error mapping embedded firmware\n"); + goto error_free_fw; + } + fw->data = kmemdup(mem, desc->length, GFP_KERNEL); + memunmap(mem); + if (!fw->data) + goto
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 05/01/2018 09:29 PM, Andy Lutomirski wrote: On Sun, Apr 29, 2018 at 2:36 AM Hans de Goede wrote: +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if the prefix is found it +then does a crc32 over length bytes and if that matches makes a copy of length +bytes and adds that to its list with found firmwares. + Eww, gross. Is there really no better way to do this? I'm afraid not. Is the issue that the EFI code does not intend to pass the firmware to the OS but that it has a copy for its own purposes and that Linux is just going to hijack EFI's copy? If so, that's brilliant and terrible at the same time. Yes that is exactly the issue / what it happening here. + for (i = 0; i < size; i += 8) { + if (*((u64 *)(mem + i)) != *((u64 *)desc->prefix)) + continue; + + /* Seed with ~0, invert to match crc32 userspace utility */ + crc = ~crc32(~0, mem + i, desc->length); + if (crc == desc->crc) + break; + } I hate to play the security card, but this stinks a bit. The kernel obviously needs to trust the EFI boot services code since the EFI boot services code is free to modify the kernel image. But your patch is not actually getting this firmware blob from the boot services code via any defined interface -- you're literally snarfing up the blob from a range of memory. I fully expect there to be any number of ways for untrustworthy entities to inject malicious blobs into this memory range on quite a few implementations. For example, there are probably unauthenticated EFI variables and even parts of USB sticks and such that get read into boot services memory, and I see no reason at all to expect that nothing in the so-called "boot services code" range is actually just plain old boot services *heap*. Fortunately, given your design, this is very easy to fix. Just replace CRC32 with SHA-256 or similar. If you find the crypto api too ugly for this purpose, I have patches that only need a small amount of dusting off to give an entirely reasonable SHA-256 API in the kernel. My main reason for going with crc32 is that the scanning happens before the kernel is fully up and running (it happens just before the rest_init() call in start_kernel() (from init/main.c) I'm open to using the crypto api, but I was not sure if that is ready for use at that time. (To be clear, I don't love my own suggestion here. What I'd *really* like to see is a better interface and no attempt to match the data to some built-in hash at all. In particular, there are plenty of devices for which the driver wants access to a genuinely device-specific blob. For example, I'm typing this email while connected to a router that is running ath10k and is using a calibration blob awkwardly snarfed out of flash somewhere. It would be really nice if there was a way to pull a blob out of EFI space that is marked, by EFI, as belonging to a particular device. Then the firmware could just pass it over without any particular verification. But since your code is literally scanning a wide swath of physical memory for something that looks like a valid blob, I think you need to use a cryptographically strong concept of validity.) Yes ideally this would not be needed at all and/or use a well defined interface, but alas we don't live in an ideal world :) Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v5 2/5] efi: Add embedded peripheral firmware support
Hi, On 01-05-18 16:36, Mimi Zohar wrote: [Cc'ing linux-security] On Sun, 2018-04-29 at 11:35 +0200, Hans de Goede wrote: [...] diff --git a/drivers/base/firmware_loader/fallback_efi.c b/drivers/base/firmware_loader/fallback_efi.c new file mode 100644 index ..82ba82f48a79 --- /dev/null +++ b/drivers/base/firmware_loader/fallback_efi.c @@ -0,0 +1,51 @@ +// SPDX-License-Identifier: GPL-2.0 + +#include +#include +#include +#include + +#include "fallback.h" +#include "firmware.h" + +int fw_get_efi_embedded_fw(struct device *dev, struct fw_priv *fw_priv, + enum fw_opt *opt_flags, int ret) +{ + enum kernel_read_file_id id = READING_FIRMWARE; Please define a new kernel_read_file_id for this (eg. READING_FIRMWARE_EFI_EMBEDDED). Are you sure, I wonder how useful it is to add a new kernel_read_file_id every time a new way to get firmware comes up? I especially wonder about the sense in adding a new id given that the quite old FIRMWARE_PREALLOC_BUFFER is still not supported / checked properly by the security code. Anyways I can add a new id if you want me to, what about when fw_get_efi_embedded_fw is reading into a driver allocated buffer, do you want a separate EADING_FIRMWARE_EFI_EMBEDDED_PREALLOC_BUFFER for that ? + size_t size, max = INT_MAX; + int rc; + + if (!dev) + return ret; + + if (!device_property_read_bool(dev, "efi-embedded-firmware")) + return ret; Instead of calling security_kernel_post_read_file(), either in device_property_read_bool() or here call security_kernel_read_file(). The pre read call is for deciding whether to allow this call independent of the firmware being loaded, whereas the post security call is currently being used by IMA-appraisal for verifying a signature. There might be other LSMs using the post hook as well. As there is no kernel signature associated with this firmware, use the security pre read_file hook. Only the pre hook? I believe the post-hook should still be called too, right? So that we've hashes of all loaded firmwares in the IMA core. Regards, Hans thanks, Mimi + + *opt_flags |= FW_OPT_NO_WARN | FW_OPT_NOCACHE | FW_OPT_NOFALLBACK; + + /* Already populated data member means we're loading into a buffer */ + if (fw_priv->data) { + id = READING_FIRMWARE_PREALLOC_BUFFER; + max = fw_priv->allocated_size; + } + + rc = efi_get_embedded_fw(fw_priv->fw_name, &fw_priv->data, &size, max); + if (rc) { + dev_warn(dev, "Firmware %s not in EFI\n", fw_priv->fw_name); + return ret; + } + + rc = security_kernel_post_read_file(NULL, fw_priv->data, size, id); + if (rc) { + if (id != READING_FIRMWARE_PREALLOC_BUFFER) { + vfree(fw_priv->data); + fw_priv->data = NULL; + } + return rc; + } + + dev_dbg(dev, "using efi-embedded fw %s\n", fw_priv->fw_name); + fw_priv->size = size; + fw_state_done(fw_priv); + return 0; +} -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 0/4] Ignore unrealistically large option roms in EFI stub code
Hi, On 29-04-18 13:06, Ard Biesheuvel wrote: This is a continuation of Hans's work [0] to ignore bogus romimage/romsize values in the EFI PCI I/O protocol instances exposed by some UEFI firmwares on x86. I have only build tested this, both on 32 and 64 bit x86. I've tested this on both a device with a 32 bit UEFI and on a device with a 64 bit UEFI, using a 64 bit kernel on both cases. The second device also used to show the "failed to alloc mem for rom" errors and I can confirm this series fixes this: Tested-by: Hans de Goede Regards, Hans Changes in v4: - Deduplicate the 32 and 64 bit code paths so that the actual change needs to be applied only once. This requires some preparatory work (#1, #2, #3), of which the first one should go to -stable. Changes in v3: - Limit the rom-size to 16MiB to match the EFI spec Changes in v2: - Add the check to both __setup_efi_pci32 and __setup_efi_pci64 instead of only to __setup_efi_pci64, some CHT devices which need this still use a 32 bit UEFI [0] https://marc.info/?l=linux-efi&m=152494632116321 Ard Biesheuvel (3): efi: fix efi_pci_io_protocol32 prototype for mixed mode efi: align efi_pci_io_protocol typedefs to type naming convention efi/x86: fold __setup_efi_pci32 and __setup_efi_pci64 into one Hans de Goede (1): efi/x86: Ignore unrealistically large option roms arch/x86/boot/compressed/eboot.c | 112 ++-- include/linux/efi.h | 14 +-- 2 files changed, 39 insertions(+), 87 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 1/5] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Reviewed-by: Greg Kroah-Hartman Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v5: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS Changes in v4: -Add new EFI_BOOT_SERVICES flag and use it to determine if the boot-services memory segments are available (and thus if it makes sense to register the debugfs bits for them) Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/efi.c| 1 + arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ include/linux/efi.h| 1 + 4 files changed, 59 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 9061babfbc83..82f0836d 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -208,6 +208,7 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_version); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); + set_bit(EFI_PRESERVE_BS_REGIONS, &efi.flags); return 0; } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..16bdb9e3b343 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -376,6 +376,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 232f4915223b..1590e4d6a857 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -325,6 +326,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -369,6 +419,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG) && efi_enabled(EFI_PRESERVE_BS_REGIONS)) + efi_debugfs_init(); + return 0; err_remove_group: diff --git a/include/linux/efi.h b/include/linux/efi.h index f1b7d68ac460..791088360c1e 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1144,6 +1144,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_DBG8 /* Print additional debug info at runtime */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ #define EFI_MEM_ATTR 10 /* Did firmware publish
[PATCH v5 2/5] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v5: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS Changes in v4: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set --- .../driver-api/firmware/request_firmware.rst | 66 drivers/base/firmware_loader/Makefile | 1 + drivers/base/firmware_loader/fallback.h | 12 ++ drivers/base/firmware_loader/fallback_efi.c | 51 ++ drivers/base/firmware_loader/main.c | 2 + drivers/firmware/efi/Kconfig | 3 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 149 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ init/main.c | 3 + 11 files changed, 319 insertions(+) create mode 100644 drivers/base/firmware_loader/fallback_efi.c create mode 100644 drivers/firmware/efi/embedded-firmware.c create mode 100644 include/linux/efi_embedded_fw.h diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index c8bddbdcfd10..560dfed76e38 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -73,3 +73,69 @@ If something w
[PATCH v5 5/5] platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
Add touchscreen info for the Chuwi Vi8 Plus tablet. This tablet uses a Chipone ICN8505 touchscreen controller, with the firmware used by the touchscreen embedded in the EFI firmware. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- drivers/platform/x86/touchscreen_dmi.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 6488cd50ba79..5fdb6fe878f4 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -301,6 +301,22 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; +static const struct property_entry efi_embedded_fw_props[] = { + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), + { } +}; + +static const struct ts_dmi_data chuwi_vi8_plus_data = { + .embedded_fw = { + .name = "chipone/icn8505-HAMP0002.fw", + .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 }, + .length = 35012, + .crc= 0x74dfd3fc, + }, + .acpi_name = "CHPN0001:00", + .properties = efi_embedded_fw_props, +}; + const struct dmi_system_id touchscreen_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -487,6 +503,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, + { + /* Chuwi Vi8 Plus (CWI506) */ + .driver_data = (void *)&chuwi_vi8_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, { }, }; -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 4/5] platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
Sofar we have been unable to get permission from the vendors to put the firmware for touchscreens listed in touchscreen_dmi in linux-firmware. Some of the tablets with such a touchscreen have a touchscreen driver, and thus a copy of the firmware, as part of their EFI code. This commit adds the necessary info for the new EFI embedded-firmware code to extract these firmwares, making the touchscreen work OOTB without the user needing to manually add the firmware. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- drivers/firmware/efi/embedded-firmware.c | 3 +++ drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/touchscreen_dmi.c | 26 +++- include/linux/efi_embedded_fw.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index 22a0f598b53d..36a93a6938f0 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -23,6 +23,9 @@ struct embedded_fw { static LIST_HEAD(found_fw_list); static const struct dmi_system_id * const embedded_fw_table[] = { +#ifdef CONFIG_TOUCHSCREEN_DMI + touchscreen_dmi_table, +#endif NULL }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7ff206e5edfe..cc4d95459190 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1199,6 +1199,7 @@ config INTEL_TURBO_MAX_3 config TOUCHSCREEN_DMI bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD + select EFI_EMBEDDED_FIRMWARE if EFI ---help--- Certain ACPI based tablets with e.g. Silead or Chipone touchscreens do not have enough data in ACPI tables for the touchscreen driver to diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 87fc839b28f7..6488cd50ba79 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include #include struct ts_dmi_data { + /* The EFI embedded-fw code expects this to be the first member! */ + struct efi_embedded_fw_desc embedded_fw; const char *acpi_name; const struct property_entry *properties; }; @@ -31,10 +34,17 @@ static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data cube_iwork8_air_data = { + .embedded_fw = { + .name = "silead/gsl3670-cube-iwork8-air.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 38808, + .crc= 0xfecde51f, + }, .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -119,10 +129,17 @@ static const struct property_entry pipo_w2s_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data pipo_w2s_data = { + .embedded_fw = { + .name = "silead/gsl1680-pipo-w2s.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39072, + .crc= 0x28d5dc6c, + }, .acpi_name = "MSSL1680:00", .properties = pipo_w2s_props, }; @@ -162,10 +179,17 @@ static const struct property_entry chuwi_hi8_pro_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data chuwi_hi8_pro_data = { + .embedded_fw = { + .name = "silead/gsl3680-chuwi-hi8-pro.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39864, + .crc= 0xfe2bedba, + }, .acpi_name = "MSSL1680:00", .properties = chuwi_hi8_pro_props, }; @@ -277,7 +301,7 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; -static const struct
[PATCH v5 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi All, Here is v5 of my patch-set to add support for EFI embedded fw to the kernel. Changes since v4: -Rename the EFI_BOOT_SERVICES flag to EFI_PRESERVE_BS_REGIONS So I think this patch-set is getting close to ready for merging, which brings us to the question of how to merge this, I think that patches 1 and 2 should probably both be merged through the same tree. Then an unmutable branch should be created on that tree, merged into the platform/x86 tree and then the last 3 patches can be merged through that tree. Ard has already indicated he is fine with the EFI bits going upstream through another tree, so perhaps patches 1-2 can be merged through the firmware-loader-tree and then do an unmutable branch on the firmware-loader-tree for the platform/x86 tree to merge? I don't think taking all 5 through 1 tree is a good idea because of the file rename under platform/x86. For the record here are the cover letters of the previous versions: Changes since v3: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it The 3 most prominent changes in v2 are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-firmware" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Patches 3-5 are new and implement using the EFI embedded-fw mechanism for Silead gsl and Chipone icn8505 touchscreens on x86 devices. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v5 3/5] platform/x86: Rename silead_dmi to touchscreen_dmi
Not only silead touchscreens need some extra info not available in the ACPI tables to work properly. X86 devices with a Chipone ICN8505 chip also need some DMI based extra configuration. There is no reason to have separate dmi config code per touchscreen controller vendor. This commit renames silead_dmi to a more generic touchscreen_dmi name (and Kconfig option) in preparation of adding info for tablets with an ICN8505 based touchscreen. Note there are no functional changes all code changes are limited to removing references to silead where these are no longer applicable. Acked-by: Andy Shevchenko Acked-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- drivers/platform/x86/Kconfig | 16 ++--- drivers/platform/x86/Makefile | 2 +- .../x86/{silead_dmi.c => touchscreen_dmi.c} | 66 +-- 4 files changed, 43 insertions(+), 43 deletions(-) rename drivers/platform/x86/{silead_dmi.c => touchscreen_dmi.c} (87%) diff --git a/MAINTAINERS b/MAINTAINERS index bee29977a3bd..5a215bcd6660 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12795,7 +12795,7 @@ L: linux-in...@vger.kernel.org L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/input/touchscreen/silead.c -F: drivers/platform/x86/silead_dmi.c +F: drivers/platform/x86/touchscreen_dmi.c SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 39d06dd1f63a..7ff206e5edfe 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..8d9477114fb5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI)+= alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC)+= intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c similarity index 87% rename from drivers/platform/x86/silead_dmi.c rename to drivers/platform/x86/touchscreen_dmi.c index 452aacabaa8e..87fc839b28f7 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,7 +20,7 @@ #include #include -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; @@ -34,7 +34,7 @@ static const struct property_entry cube_iwork8_air_props[] = { { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -48,7 +48,7 @@ static const struct property_entry jumper_ezpad_mini3_props[] = { { } }; -static const struct silead_ts
Re: [PATCH v3] efi: Ignore unrealistically large option roms
Hi, On 29-04-18 11:07, Ard Biesheuvel wrote: On 29 April 2018 at 10:40, Hans de Goede wrote: Hi, On 29-04-18 09:43, Ingo Molnar wrote: * Hans de Goede wrote: diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 47d3efff6805..8650ab268ee7 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -122,7 +122,14 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); @@ -230,7 +237,14 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; Any reason why this couldn't be factored out into a efi_check_rom(pci) kind of helper function The pci pointer is of 2 different types: __setup_efi_pci32(efi_pci_io_protocol_32 *pci, ... __setup_efi_pci64(efi_pci_io_protocol_64 *pci, ... I guess I could give the helper a romimage and romsize argument to get around that. Ard, do you want me to do a v4 with such a helper ? I think Lukas has a point, although I shouldn't expect you to implement that. I will look into this myself, and rebase your patch on top of that. Ok, thanks. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3] efi: Ignore unrealistically large option roms
Hi, On 29-04-18 09:43, Ingo Molnar wrote: * Hans de Goede wrote: diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 47d3efff6805..8650ab268ee7 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -122,7 +122,14 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); @@ -230,7 +237,14 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; Any reason why this couldn't be factored out into a efi_check_rom(pci) kind of helper function The pci pointer is of 2 different types: __setup_efi_pci32(efi_pci_io_protocol_32 *pci, ... __setup_efi_pci64(efi_pci_io_protocol_64 *pci, ... I guess I could give the helper a romimage and romsize argument to get around that. Ard, do you want me to do a v4 with such a helper ? Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3] efi: Ignore unrealistically large option roms
setup_efi_pci() tries to save a copy of each PCI option ROM as this may be necessary for the device driver for the PCI device to have access too. On some systems the efi_pci_io_protocol's romimage and romsize fields contain invalid data, which looks a bit like pointers pointing back into other EFI code or data. Interpreting these pointers as romsize leads to a very large value and if we then try to alloc this amount of memory to save a copy the alloc call fails. This leads to a "Failed to alloc mem for rom" error being printed on the EFI console for each PCI device. This commit avoids the printing of these errors, by checking romsize before doing the alloc and if it is larger then the EFI spec limit of 16 MiB silently ignore the ROM fields instead of trying to alloc mem and fail. Reviewed-by: Ard Biesheuvel Signed-off-by: Hans de Goede --- Changes in v3: -Limit the rom-size to 16MiB to match the EFI spec Changes in v2: -Add the check to both __setup_efi_pci32 and __setup_efi_pci64 instead of only to __setup_efi_pci64, some CHT devices which need this still use a 32 bit UEFI --- arch/x86/boot/compressed/eboot.c | 18 -- 1 file changed, 16 insertions(+), 2 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 47d3efff6805..8650ab268ee7 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -122,7 +122,14 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); @@ -230,7 +237,14 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. The UEFI spec limits the size of option ROMs to 16 +* MiB so we reject any roms over 16 MiB in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x100) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v2] efi: Ignore unrealistically large option roms
Hi, On 28-04-18 08:40, Ard Biesheuvel wrote: Hi Hans, On 27 April 2018 at 23:35, Hans de Goede wrote: setup_efi_pci() tries to save a copy of each PCI option ROM as this may be necessary for the device driver for the PCI device to have access too. On some systems the efi_pci_io_protocol_64's romimage and romsize fields contain invalid data, which looks a bit like pointers pointing back into other EFI code or data. Interpreting these pointers as romsize leads to a very large value and if we then try to alloc this amount of memory to save a copy the alloc call fails. This leads to a "Failed to alloc mem for rom" error being printed on the EFI console for each PCI device. This commit avoids the printing of these errors, by checking romsize before doing the alloc and if it is larger then 256M silently ignore the ROM fields instead of trying to alloc mem and fail. The UEFI spec limits the size of option ROMs to 16 MiB, so I'd prefer we use that as the upper bound instead. With that changed, Reviewed-by: Ard Biesheuvel Thanks for the review, fixed for v3 which I'm about to send. or I can take it via the EFI tree if desired. I've no preference for how this goes upstream. x86 folks, please let us know if you will take this, or if you would prefer for this to go upstream through the EFI tree. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2] efi: Ignore unrealistically large option roms
setup_efi_pci() tries to save a copy of each PCI option ROM as this may be necessary for the device driver for the PCI device to have access too. On some systems the efi_pci_io_protocol_64's romimage and romsize fields contain invalid data, which looks a bit like pointers pointing back into other EFI code or data. Interpreting these pointers as romsize leads to a very large value and if we then try to alloc this amount of memory to save a copy the alloc call fails. This leads to a "Failed to alloc mem for rom" error being printed on the EFI console for each PCI device. This commit avoids the printing of these errors, by checking romsize before doing the alloc and if it is larger then 256M silently ignore the ROM fields instead of trying to alloc mem and fail. Signed-off-by: Hans de Goede --- Changes in v2: -Add the check to both __setup_efi_pci32 and __setup_efi_pci64 instead of only to __setup_efi_pci64, some CHT devices which need this still use a 32 bit UEFI --- arch/x86/boot/compressed/eboot.c | 16 ++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 47d3efff6805..6d3257a459c8 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -122,7 +122,13 @@ __setup_efi_pci32(efi_pci_io_protocol_32 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. We reject any roms over 256M in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x1000) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); @@ -230,7 +236,13 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. We reject any roms over 256M in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x1000) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); -- 2.16.2 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 1/5] efi: Export boot-services code and data as debugfs-blobs
Hi, On 26-04-18 23:35, Ard Biesheuvel wrote: On 26 April 2018 at 23:02, Hans de Goede wrote: Hi, On 26-04-18 18:51, Ard Biesheuvel wrote: On 26 April 2018 at 14:06, Hans de Goede wrote: Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Hans de Goede --- Changes in v4: -Add new EFI_BOOT_SERVICES flag and use it to determine if the boot-services memory segments are available (and thus if it makes sense to register the debugfs bits for them) Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/efi.c| 1 + arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ include/linux/efi.h| 1 + 4 files changed, 59 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 9061babfbc83..568b7ee3d323 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -208,6 +208,7 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_version); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); + set_bit(EFI_BOOT_SERVICES, &efi.flags); I think it would be better if the flag conveys whether boot services regions are being preserved, because they will always exist when EFI_BOOT is set. The name should then reflect that as well, e.g., EFI_PRESERVE_BS_REGIONS. Ok, I will rename the flag to EFI_PRESERVE_BS_REGIONS for v5 (I'm going to wait a bit with sending out v5 to give others a change to comment on v4). return 0; } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..16bdb9e3b343 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -376,6 +376,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + Why is this only necessary when EFI_DBG is enabled? How are you ensuring that the firmware is still in memory when the subsequent patches start relying on that? The 2nd patch in this series makes init/main.c call efi_check_for_embedded_firmwares() before efi_free_boot_services(), efi_check_for_embedded_firmwares() then walks the dmi_system_id-s "registered" (its a static list) by drivers and if their is a dmi_match searches for the firmware described by the dmi_system_id.driver_data ptr. If a firmware gets found it gets memdup-ed, so that we do not have to keep all of the boot-services code around. Right, thanks for clearing that up. So that means that preserving the boot regions is really only necessary if you want to inspect them via debugfs, and the firmware loader does not rely on that. I missed that part. That means the only reason we have the new flag is to ensure that the shared debugfs code only exposes the boot services regions if they were preserved to begin with by the arch code, right? Mostly right, since we have the flag now anyways I'm also using it as a condition to call efi_check_for_embedded_firmwares(), efi_check_for_embedded_firmwares() needs to happen after mm_init() (*) and on non x86 the boot-services code/data is long gone then so there is nothing for efi_check_for_embedded_firmwares() to look at. If so, after the flag rename: Acked-by: Ard Biesheuvel I assume that the "mostly right" is good enough and I'm going to add your Acked-by for the next version. Let me know if you've any objections against that. Regards, Hans *) efi_check_for_embedded_firmwares() mremap()s the boot-services memory segments to scan then and they are too big for early_mremap() -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v4 1/5] efi: Export boot-services code and data as debugfs-blobs
Hi, On 26-04-18 18:51, Ard Biesheuvel wrote: On 26 April 2018 at 14:06, Hans de Goede wrote: Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Hans de Goede --- Changes in v4: -Add new EFI_BOOT_SERVICES flag and use it to determine if the boot-services memory segments are available (and thus if it makes sense to register the debugfs bits for them) Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/efi.c| 1 + arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ include/linux/efi.h| 1 + 4 files changed, 59 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 9061babfbc83..568b7ee3d323 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -208,6 +208,7 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_version); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); + set_bit(EFI_BOOT_SERVICES, &efi.flags); I think it would be better if the flag conveys whether boot services regions are being preserved, because they will always exist when EFI_BOOT is set. The name should then reflect that as well, e.g., EFI_PRESERVE_BS_REGIONS. Ok, I will rename the flag to EFI_PRESERVE_BS_REGIONS for v5 (I'm going to wait a bit with sending out v5 to give others a change to comment on v4). return 0; } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..16bdb9e3b343 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -376,6 +376,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + Why is this only necessary when EFI_DBG is enabled? How are you ensuring that the firmware is still in memory when the subsequent patches start relying on that? The 2nd patch in this series makes init/main.c call efi_check_for_embedded_firmwares() before efi_free_boot_services(), efi_check_for_embedded_firmwares() then walks the dmi_system_id-s "registered" (its a static list) by drivers and if their is a dmi_match searches for the firmware described by the dmi_system_id.driver_data ptr. If a firmware gets found it gets memdup-ed, so that we do not have to keep all of the boot-services code around. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 2/5] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- Changes in v4: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set --- .../driver-api/firmware/request_firmware.rst | 66 drivers/base/firmware_loader/Makefile | 1 + drivers/base/firmware_loader/fallback.h | 12 ++ drivers/base/firmware_loader/fallback_efi.c | 51 ++ drivers/base/firmware_loader/main.c | 4 + drivers/firmware/efi/Kconfig | 3 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 152 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ init/main.c | 3 + 11 files changed, 324 insertions(+) create mode 100644 drivers/base/firmware_loader/fallback_efi.c create mode 100644 drivers/firmware/efi/embedded-firmware.c create mode 100644 include/linux/efi_embedded_fw.h diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index c8bddbdcfd10..560dfed76e38 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -73,3 +73,69 @@ If something went wrong firmware_request() returns non-zero and fw_entry is set to NULL. Once your driver is d
[PATCH v4 1/5] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Reviewed-by: Greg Kroah-Hartman Signed-off-by: Hans de Goede --- Changes in v4: -Add new EFI_BOOT_SERVICES flag and use it to determine if the boot-services memory segments are available (and thus if it makes sense to register the debugfs bits for them) Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/efi.c| 1 + arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ include/linux/efi.h| 1 + 4 files changed, 59 insertions(+) diff --git a/arch/x86/platform/efi/efi.c b/arch/x86/platform/efi/efi.c index 9061babfbc83..568b7ee3d323 100644 --- a/arch/x86/platform/efi/efi.c +++ b/arch/x86/platform/efi/efi.c @@ -208,6 +208,7 @@ int __init efi_memblock_x86_reserve_range(void) efi.memmap.desc_version); memblock_reserve(pmap, efi.memmap.nr_map * efi.memmap.desc_size); + set_bit(EFI_BOOT_SERVICES, &efi.flags); return 0; } diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 36c1f8b9f7e0..16bdb9e3b343 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -376,6 +376,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index 232f4915223b..498a720a7684 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -325,6 +326,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -369,6 +419,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG) && efi_enabled(EFI_BOOT_SERVICES)) + efi_debugfs_init(); + return 0; err_remove_group: diff --git a/include/linux/efi.h b/include/linux/efi.h index f1b7d68ac460..396bf18ace5c 100644 --- a/include/linux/efi.h +++ b/include/linux/efi.h @@ -1144,6 +1144,7 @@ extern int __init efi_setup_pcdp_console(char *); #define EFI_DBG8 /* Print additional debug info at runtime */ #define EFI_NX_PE_DATA 9 /* Can runtime data regions be mapped non-executable? */ #define EFI_MEM_ATTR 10 /* Did firmware publish an EFI_MEMORY_ATTRIBUTES table? */ +#define EFI_BOOT_SERVICES 11 /* Are EFI boot-services memory segments avai
[PATCH v4 4/5] platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
Sofar we have been unable to get permission from the vendors to put the firmware for touchscreens listed in touchscreen_dmi in linux-firmware. Some of the tablets with such a touchscreen have a touchscreen driver, and thus a copy of the firmware, as part of their EFI code. This commit adds the necessary info for the new EFI embedded-firmware code to extract these firmwares, making the touchscreen work OOTB without the user needing to manually add the firmware. Acked-by: Andy Shevchenko Signed-off-by: Hans de Goede --- drivers/firmware/efi/embedded-firmware.c | 3 +++ drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/touchscreen_dmi.c | 26 +++- include/linux/efi_embedded_fw.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index ef6282945307..bbc6d218a82d 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -23,6 +23,9 @@ struct embedded_fw { static LIST_HEAD(found_fw_list); static const struct dmi_system_id * const embedded_fw_table[] = { +#ifdef CONFIG_TOUCHSCREEN_DMI + touchscreen_dmi_table, +#endif NULL }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 7ff206e5edfe..cc4d95459190 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1199,6 +1199,7 @@ config INTEL_TURBO_MAX_3 config TOUCHSCREEN_DMI bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD + select EFI_EMBEDDED_FIRMWARE if EFI ---help--- Certain ACPI based tablets with e.g. Silead or Chipone touchscreens do not have enough data in ACPI tables for the touchscreen driver to diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 87fc839b28f7..6488cd50ba79 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include #include struct ts_dmi_data { + /* The EFI embedded-fw code expects this to be the first member! */ + struct efi_embedded_fw_desc embedded_fw; const char *acpi_name; const struct property_entry *properties; }; @@ -31,10 +34,17 @@ static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data cube_iwork8_air_data = { + .embedded_fw = { + .name = "silead/gsl3670-cube-iwork8-air.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 38808, + .crc= 0xfecde51f, + }, .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -119,10 +129,17 @@ static const struct property_entry pipo_w2s_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data pipo_w2s_data = { + .embedded_fw = { + .name = "silead/gsl1680-pipo-w2s.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39072, + .crc= 0x28d5dc6c, + }, .acpi_name = "MSSL1680:00", .properties = pipo_w2s_props, }; @@ -162,10 +179,17 @@ static const struct property_entry chuwi_hi8_pro_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data chuwi_hi8_pro_data = { + .embedded_fw = { + .name = "silead/gsl3680-chuwi-hi8-pro.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39864, + .crc= 0xfe2bedba, + }, .acpi_name = "MSSL1680:00", .properties = chuwi_hi8_pro_props, }; @@ -277,7 +301,7 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; -static const struct dmi_system_id touchs
[PATCH v4 3/5] platform/x86: Rename silead_dmi to touchscreen_dmi
Not only silead touchscreens need some extra info not available in the ACPI tables to work properly. X86 devices with a Chipone ICN8505 chip also need some DMI based extra configuration. There is no reason to have separate dmi config code per touchscreen controller vendor. This commit renames silead_dmi to a more generic touchscreen_dmi name (and Kconfig option) in preparation of adding info for tablets with an ICN8505 based touchscreen. Note there are no functional changes all code changes are limited to removing references to silead where these are no longer applicable. Acked-by: Andy Shevchenko Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- drivers/platform/x86/Kconfig | 16 ++--- drivers/platform/x86/Makefile | 2 +- .../x86/{silead_dmi.c => touchscreen_dmi.c} | 66 +-- 4 files changed, 43 insertions(+), 43 deletions(-) rename drivers/platform/x86/{silead_dmi.c => touchscreen_dmi.c} (87%) diff --git a/MAINTAINERS b/MAINTAINERS index bee29977a3bd..5a215bcd6660 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12795,7 +12795,7 @@ L: linux-in...@vger.kernel.org L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/input/touchscreen/silead.c -F: drivers/platform/x86/silead_dmi.c +F: drivers/platform/x86/touchscreen_dmi.c SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 39d06dd1f63a..7ff206e5edfe 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1196,16 +1196,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..8d9477114fb5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI)+= alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC)+= intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c similarity index 87% rename from drivers/platform/x86/silead_dmi.c rename to drivers/platform/x86/touchscreen_dmi.c index 452aacabaa8e..87fc839b28f7 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,7 +20,7 @@ #include #include -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; @@ -34,7 +34,7 @@ static const struct property_entry cube_iwork8_air_props[] = { { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -48,7 +48,7 @@ static const struct property_entry jumper_ezpad_mini3_props[] = { { } }; -static const struct silead_ts_dmi_data jumper_ezpad_m
[PATCH v4 5/5] platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
Add touchscreen info for the Chuwi Vi8 Plus tablet. This tablet uses a Chipone ICN8505 touchscreen controller, with the firmware used by the touchscreen embedded in the EFI firmware. Acked-by: Andy Shevchenko Signed-off-by: Hans de Goede --- drivers/platform/x86/touchscreen_dmi.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 6488cd50ba79..5fdb6fe878f4 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -301,6 +301,22 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; +static const struct property_entry efi_embedded_fw_props[] = { + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), + { } +}; + +static const struct ts_dmi_data chuwi_vi8_plus_data = { + .embedded_fw = { + .name = "chipone/icn8505-HAMP0002.fw", + .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 }, + .length = 35012, + .crc= 0x74dfd3fc, + }, + .acpi_name = "CHPN0001:00", + .properties = efi_embedded_fw_props, +}; + const struct dmi_system_id touchscreen_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -487,6 +503,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, + { + /* Chuwi Vi8 Plus (CWI506) */ + .driver_data = (void *)&chuwi_vi8_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, { }, }; -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v4 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi All, Here is v4 of my patch-set to add support for EFI embedded fw to the kernel. Changes since v3: -Drop note in docs about EFI_FIRMWARE_VOLUME_PROTOCOL, it is not part of UEFI proper, so the EFI maintainers don't want us referring people to it -Use new EFI_BOOT_SERVICES flag -Put the new fw_get_efi_embedded_fw() function in its own fallback_efi.c file which only gets built when EFI_EMBEDDED_FIRMWARE is selected -Define an empty stub for fw_get_efi_embedded_fw() in fallback.h hwen EFI_EMBEDDED_FIRMWARE is not selected, to avoid the need for #ifdefs in firmware_loader/main.c -Properly call security_kernel_post_read_file() on the firmware returned by efi_get_embedded_fw() to make sure that we are allowed to use it So I think this patch-set is getting close to ready for merging, which brings us to the question of how to merge this, I think that patches 1 and 2 should probably both be merged through the same tree. Then an unmutable branch should be created on that tree, merged into the platform/x86 tree and then the last 3 patches can be merged through that tree. For the record, here is the coverletter of v2 of this patchset: The 3 most prominent changes in v2 are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-firmware" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Patches 3-5 are new and implement using the EFI embedded-fw mechanism for Silead gsl and Chipone icn8505 touchscreens on x86 devices. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/5] efi: Add embedded peripheral firmware support
Hi, On 24-04-18 18:07, Mimi Zohar wrote: On Tue, 2018-04-24 at 17:09 +0200, Hans de Goede wrote: Hi, On 23-04-18 23:11, Luis R. Rodriguez wrote: Hans, please see use of READING_FIRMWARE_PREALLOC_BUFFER, we'll need a new ID and security for this type of request so IMA can reject it if the policy is configured for it. Hmm, interesting, actually it seems like the whole existence of READING_FIRMWARE_PREALLOC_BUFFER is a mistake, the IMA framework really does not care if we are loading the firmware into memory allocated by the firmware-loader code, or into memory allocated by the device-driver requesting the firmware. As such the current IMA code (from v4.17-rc2) actually does not handle READING_FIRMWARE_PREALLOC_BUFFER at all, Right, it doesn't yet address READING_FIRMWARE_PREALLOC_BUFFER, but should. Depending on whether the device requesting the firmware has access to the DMA memory, before the signature verification, will determine how IMA-appraisal addresses READING_FIRMWARE_PREALLOC_BUFFER. Ah I see. So this probably means that the IMA integration for my EFI embedded firmware code should also pass READING_FIRMWARE or READING_FIRMWARE_PREALLOC_BUFFER depending on if a pre-allocated buffer is used. Hmm, the security_kernel_post_read_file() call in drivers/base/firmware_loader/fallback.c Unconditionally passes READING_FIRMWARE, it should probably check fw_priv->is_paged_buf and base the id to pass on that. And yes it is possible AFAICT for the firmware_request_into_buf() method to fallback to the userspace helper, this can happen if the fw_fallback_config.force_sysfs_fallback flag is set. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/5] efi: Add embedded peripheral firmware support
Hi, On 23-04-18 23:11, Luis R. Rodriguez wrote: Hans, please see use of READING_FIRMWARE_PREALLOC_BUFFER, we'll need a new ID and security for this type of request so IMA can reject it if the policy is configured for it. Hmm, interesting, actually it seems like the whole existence of READING_FIRMWARE_PREALLOC_BUFFER is a mistake, the IMA framework really does not care if we are loading the firmware into memory allocated by the firmware-loader code, or into memory allocated by the device-driver requesting the firmware. As such the current IMA code (from v4.17-rc2) actually does not handle READING_FIRMWARE_PREALLOC_BUFFER at all, here are bits of code from: security/integrity/ima/ima_main.c: static int read_idmap[READING_MAX_ID] = { [READING_FIRMWARE] = FIRMWARE_CHECK, [READING_MODULE] = MODULE_CHECK, [READING_KEXEC_IMAGE] = KEXEC_KERNEL_CHECK, [READING_KEXEC_INITRAMFS] = KEXEC_INITRAMFS_CHECK, [READING_POLICY] = POLICY_CHECK }; int ima_post_read_file(struct file *file, void *buf, loff_t size, ... if (!file && read_id == READING_FIRMWARE) { if ((ima_appraise & IMA_APPRAISE_FIRMWARE) && (ima_appraise & IMA_APPRAISE_ENFORCE)) return -EACCES; /* INTEGRITY_UNKNOWN */ return 0; } Which show that the IMA code is not handling READING_FIRMWARE_PREALLOC_BUFFER as it should (I believe it should handle it the same as READING_FIRMWARE). Now we could fix that, but the only user of READING_FIRMWARE_PREALLOC_BUFFER is the code which originally introduced it: https://patchwork.kernel.org/patch/9162011/ So I believe it might be better to instead replace it with just READING_FIRMWARE and find another way to tell kernel_read_file() that there is a pre-allocated buffer, perhaps the easiest way there is that *buf must be NULL when the caller wants kernel_read_file() to vmalloc the mem. This would of course require auditing all callers that the buf which the pass in is initialized to NULL. Either way adding a third READING_FIRMWARE_FOO to the kernel_read_file_id enum seems like a bad idea, from the IMA pov firmware is firmware. What this whole exercise has shown me though is that I need to call security_kernel_post_read_file() when loading EFI embedded firmware. I will add a call to security_kernel_post_read_file() for v4 of the patch-set. Please Cc Kees in future patches. Will do. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/5] efi: Add embedded peripheral firmware support
Hi, On 16-04-18 10:28, Ard Biesheuvel wrote: On 8 April 2018 at 19:40, Hans de Goede wrote: Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" --- .../driver-api/firmware/request_firmware.rst | 70 + drivers/base/firmware_loader/main.c | 33 drivers/firmware/efi/Kconfig | 6 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 148 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ init/main.c | 1 + 8 files changed, 290 insertions(+) create mode 100644 drivers/firmware/efi/embedded-firmware.c create mode 100644 include/linux/efi_embedded_fw.h diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index 20f21ed427a5..189b02f815c9 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -68,3 +68,73 @@ If something went wrong request_firmware() returns non-zero and fw_entry is set to NULL. Once your driver is done with processing the firmware it can call call release_firmware(fw_entry) to release the firmware image and any related resource. + +EFI embedded firmware support += + +On some devices the system's EFI code / ROM may contain an embedded copy +of firmware for some of the system's integrated peripheral devices and +the peripheral's Linux device-driver needs to access this firmware. + +A device driver which needs this can describe the firmware it needs +using an efi_embedded_fw_desc struct: + +.. kernel-doc:: include/linux/efi_embedded_fw.h + :functions: efi_embedded_fw_desc + +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if
Re: [PATCH v3 1/5] efi: Export boot-services code and data as debugfs-blobs
Hi, On 16-04-18 10:23, Ard Biesheuvel wrote: Hallo Hans, On 8 April 2018 at 19:40, Hans de Goede wrote: Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Signed-off-by: Hans de Goede --- Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ 2 files changed, 57 insertions(+) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..0f968c7bcfec 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -374,6 +374,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index cd42f66a7c85..10c896e8b82b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -360,6 +410,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG)) + efi_debugfs_init(); + This doesn't really make any sense on non-x86. The boot services regions are released to the kernel for general allocation, and so exposing them this way only makes sense if you keep them as you do for x86. Could you please try to make this call specific to situations where it makes sense? I don't mind allocating a new EFI_xxx flag for preserving the boot services regions so we could decide to set it for ARM/arm64 as well in certain cases in the future. Ok, I've added a new EFI_BOOT_SERVICES flag for this for v4 of this patchset, mirroring the existing EFI_RUNTIME_SERVICES flag in naming. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/5] efi: Add embedded peripheral firmware support
Hi, On 17-04-18 02:17, Luis R. Rodriguez wrote: On Sun, Apr 08, 2018 at 07:40:11PM +0200, Hans de Goede wrote: static void firmware_free_data(const struct firmware *fw) { @@ -576,6 +600,15 @@ _request_firmware(const struct firmware **firmware_p, const char *name, goto out; ret = fw_get_filesystem_firmware(device, fw->priv); +#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE + if (ret && device && + device_property_read_bool(device, "efi-embedded-firmware")) { + ret = fw_get_efi_embedded_fw(device, fw->priv, ret); + if (ret == 0) + ret = assign_fw(fw, device, opt_flags | FW_OPT_NOCACHE); + goto out; + } +#endif So thinking some more about this, I can put the device_property check inside the fw_get_efi_embedded_fw() call, as well as modify opt_flags there to or in FW_OPT_NOCACHE on success, then together with the discussed changed to drop the #ifdef, the code would look like this: ret = fw_get_filesystem_firmware(device, fw->priv); if (ret) fw_get_efi_embedded_fw(device, fw->priv, &opt_flags, ret); if (ret) if (!(opt_flags & FW_OPT_NO_WARN)) dev_warn(device, ... With just these 2 lines being new: if (ret) fw_get_efi_embedded_fw(device, fw->priv, &opt_flags, ret); So the main.c changes will be nice and clean then. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH v3 2/5] efi: Add embedded peripheral firmware support
Hi, On 17-04-18 02:17, Luis R. Rodriguez wrote: On Sun, Apr 08, 2018 at 07:40:11PM +0200, Hans de Goede wrote: static void firmware_free_data(const struct firmware *fw) { @@ -576,6 +600,15 @@ _request_firmware(const struct firmware **firmware_p, const char *name, goto out; ret = fw_get_filesystem_firmware(device, fw->priv); +#ifdef CONFIG_EFI_EMBEDDED_FIRMWARE + if (ret && device && + device_property_read_bool(device, "efi-embedded-firmware")) { + ret = fw_get_efi_embedded_fw(device, fw->priv, ret); + if (ret == 0) + ret = assign_fw(fw, device, opt_flags | FW_OPT_NOCACHE); + goto out; + } +#endif You mussed what I asked for in terms of adding a new flag, (please work on top of Andre's patches as those likely will be merged first, and also have kdocs for the flags) Ok I will base my next version on top of Andres' series. and then a new firmware API to wrap the above into a function which would only do something if the driver *asked* for it on their firmware API call. Ie, please add a new firmware_request_efi_fw(). As I tried to explain in the changelog the problem with doing this, is that this makes it a driver decision, where it really needs to be platform-code driven, not driver driven. Take for example the drivers/input/touchscreen/silead.c code that is used on a lot of 32 bit ARM platforms too, which don't have EFI at all, so if that needs to call request_firmware_efi() then should I add: #ifdef CONFIG_X86 fw = request_firmware_efi(...); #else fw = request_firmware(...); #endif ? But even on x86 only some devices with a silead touchscreen have EFI embedded firmware, so then I would need something like: #ifdef CONFIG_X86 if (device_property_get_bool(dev, "some-prop-name")) fw = request_firmware_efi(...); else #else fw = request_firmware(...); #endif That is assuming I still want the normal fallback path in the case no EFI firmware is available, which I do because then something like packagekit may see if the firmware is packaged in one of the configured distro repositories. We already have (x86) platform code in place to attach properties (like a board specific firmware filename) to the device using device-properties so that drivers like silead.c don't get filled / polluted with board/platform specific knowledge, which IMHO is the place where the knowledge fallback to an EFI embedded firmware copy belongs. As the further patches in v3 of this series shows, this actually works quite nicely, because this also allows bundling the EFI-embedded firmware info (prefix, length, crc, name) together with the other board specific properties. TL;DR: using request_firmware_efi() vs request_firmware() is a driver decision, but whether EFI firmware fallback should be is board/platform specific not driver specific, therefor I believe that using a device-property to signal this is better. If you insist on me adding a request_firmware_efi() I can give this a shot, but I know that Dmitry (the input maintainer) will very much dislike the silead.c changes that implies... Still a question for lets sat we go that route, what do we then do with request_firmware_efi() when CONFIG_EFI is not set ? Should it be defined then or not, and if it should be defined when CONFIG_EFI is not set what should it do then? Also if you see the work I've done to remove the ifdefs over fallback mechanism you'll see it helps split code and make it easier to read. We should strive to not add any more ifdefery and instead make tehis code read easily. So looking at how the CONFIG_FW_LOADER_USER_HELPER stuff deals with this, I should: 1) Move the definition of fw_get_efi_embedded_fw() to a new drivers/base/firmware_loader/fallback_efi.c, which only gets build if CONFIG_EFI_EMBEDDED_FIRMWARE is set 2) Put the following in fallback.h: #ifdef CONFIG_EFI_EMBEDDED_FIRMWARE int fw_get_efi_embedded_fw(struct device *dev, struct fw_priv *fw_priv, int ret); #else static inline int fw_get_efi_embedded_fw(struct device *dev, struct fw_priv *fw_priv, int ret) { return ret; } #endif have I got that right? Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 1/5] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Signed-off-by: Hans de Goede --- Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ 2 files changed, 57 insertions(+) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..0f968c7bcfec 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -374,6 +374,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index cd42f66a7c85..10c896e8b82b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -360,6 +410,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG)) + efi_debugfs_init(); + return 0; err_remove_group: -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 3/5] platform/x86: Rename silead_dmi to touchscreen_dmi
Not only silead touchscreens need some extra info not available in the ACPI tables to work properly. X86 devices with a Chipone ICN8505 chip also need some DMI based extra configuration. There is no reason to have separate dmi config code per touchscreen controller vendor. This commit renames silead_dmi to a more generic touchscreen_dmi name (and Kconfig option) in preparation of adding info for tablets with an ICN8505 based touchscreen. Note there are no functional changes all code changes are limited to removing references to silead where these are no longer applicable. Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- drivers/platform/x86/Kconfig | 16 ++--- drivers/platform/x86/Makefile | 2 +- .../x86/{silead_dmi.c => touchscreen_dmi.c} | 66 +-- 4 files changed, 43 insertions(+), 43 deletions(-) rename drivers/platform/x86/{silead_dmi.c => touchscreen_dmi.c} (87%) diff --git a/MAINTAINERS b/MAINTAINERS index 0d5c55daeeba..99dd47e3b0dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12618,7 +12618,7 @@ L: linux-in...@vger.kernel.org L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/input/touchscreen/silead.c -F: drivers/platform/x86/silead_dmi.c +F: drivers/platform/x86/touchscreen_dmi.c SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1868aab0282a..b836576f0fe4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1194,16 +1194,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..8d9477114fb5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI)+= alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC)+= intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c similarity index 87% rename from drivers/platform/x86/silead_dmi.c rename to drivers/platform/x86/touchscreen_dmi.c index 452aacabaa8e..87fc839b28f7 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,7 +20,7 @@ #include #include -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; @@ -34,7 +34,7 @@ static const struct property_entry cube_iwork8_air_props[] = { { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -48,7 +48,7 @@ static const struct property_entry jumper_ezpad_mini3_props[] = { { } }; -static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { +static c
[PATCH v3 2/5] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Changes in v3: -Fix the docs using "efi-embedded-fw" as property name instead of "efi-embedded-firmware" --- .../driver-api/firmware/request_firmware.rst | 70 + drivers/base/firmware_loader/main.c | 33 drivers/firmware/efi/Kconfig | 6 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 148 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ init/main.c | 1 + 8 files changed, 290 insertions(+) create mode 100644 drivers/firmware/efi/embedded-firmware.c create mode 100644 include/linux/efi_embedded_fw.h diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index 20f21ed427a5..189b02f815c9 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -68,3 +68,73 @@ If something went wrong request_firmware() returns non-zero and fw_entry is set to NULL. Once your driver is done with processing the firmware it can call call release_firmware(fw_entry) to release the firmware image and any related resource. + +EFI embedded firmware support += + +On some devices the system's EFI code / ROM may contain an embedded copy +of firmware for some of the system's integrated peripheral devices and +the peripheral's Linux device-driver needs to access this firmware. + +A device driver which needs this can describe the firmware it needs +using an efi_embedded_fw_desc struct: + +.. kernel-doc:: include/linux/efi_embedded_fw.h + :functions: efi_embedded_fw_desc + +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if the prefix is found it +then does a crc32 over length bytes and if that matches makes a copy of length +bytes and adds t
[PATCH v3 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi All, Sorry for sending a v3 so soon after v2, I got the property name wrong in the documentation added in v2 and of course noticed that minutes after sending v2. This version fixes this. Here is the v2 coverletter again: Here is v2 of my patch-set to add support for EFI embedded fw to the kernel. The 3 most prominent changes are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-firmware" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-firmware" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Patches 3-5 are new and implement using the EFI embedded-fw mechanism for Silead gsl and Chipone icn8505 touchscreens on x86 devices. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 5/5] platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
Add touchscreen info for the Chuwi Vi8 Plus tablet. This tablet uses a Chipone ICN8505 touchscreen controller, with the firmware used by the touchscreen embedded in the EFI firmware. Signed-off-by: Hans de Goede --- drivers/platform/x86/touchscreen_dmi.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 6488cd50ba79..5fdb6fe878f4 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -301,6 +301,22 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; +static const struct property_entry efi_embedded_fw_props[] = { + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), + { } +}; + +static const struct ts_dmi_data chuwi_vi8_plus_data = { + .embedded_fw = { + .name = "chipone/icn8505-HAMP0002.fw", + .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 }, + .length = 35012, + .crc= 0x74dfd3fc, + }, + .acpi_name = "CHPN0001:00", + .properties = efi_embedded_fw_props, +}; + const struct dmi_system_id touchscreen_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -487,6 +503,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, + { + /* Chuwi Vi8 Plus (CWI506) */ + .driver_data = (void *)&chuwi_vi8_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, { }, }; -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v3 4/5] platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
Sofar we have been unable to get permission from the vendors to put the firmware for touchscreens listed in touchscreen_dmi in linux-firmware. Some of the tablets with such a touchscreen have a touchscreen driver, and thus a copy of the firmware, as part of their EFI code. This commit adds the necessary info for the new EFI embedded-firmware code to extract these firmwares, making the touchscreen work OOTB without the user needing to manually add the firmware. Signed-off-by: Hans de Goede --- drivers/firmware/efi/embedded-firmware.c | 3 +++ drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/touchscreen_dmi.c | 26 +++- include/linux/efi_embedded_fw.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index cb57225a340d..26101ac1a282 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -23,6 +23,9 @@ struct embedded_fw { static LIST_HEAD(found_fw_list); static const struct dmi_system_id * const embedded_fw_table[] = { +#ifdef CONFIG_TOUCHSCREEN_DMI + touchscreen_dmi_table, +#endif NULL }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b836576f0fe4..5bb0f5edd7f2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1197,6 +1197,7 @@ config INTEL_TURBO_MAX_3 config TOUCHSCREEN_DMI bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD + select EFI_EMBEDDED_FIRMWARE if EFI_STUB ---help--- Certain ACPI based tablets with e.g. Silead or Chipone touchscreens do not have enough data in ACPI tables for the touchscreen driver to diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 87fc839b28f7..6488cd50ba79 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include #include struct ts_dmi_data { + /* The EFI embedded-fw code expects this to be the first member! */ + struct efi_embedded_fw_desc embedded_fw; const char *acpi_name; const struct property_entry *properties; }; @@ -31,10 +34,17 @@ static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data cube_iwork8_air_data = { + .embedded_fw = { + .name = "silead/gsl3670-cube-iwork8-air.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 38808, + .crc= 0xfecde51f, + }, .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -119,10 +129,17 @@ static const struct property_entry pipo_w2s_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data pipo_w2s_data = { + .embedded_fw = { + .name = "silead/gsl1680-pipo-w2s.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39072, + .crc= 0x28d5dc6c, + }, .acpi_name = "MSSL1680:00", .properties = pipo_w2s_props, }; @@ -162,10 +179,17 @@ static const struct property_entry chuwi_hi8_pro_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data chuwi_hi8_pro_data = { + .embedded_fw = { + .name = "silead/gsl3680-chuwi-hi8-pro.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39864, + .crc= 0xfe2bedba, + }, .acpi_name = "MSSL1680:00", .properties = chuwi_hi8_pro_props, }; @@ -277,7 +301,7 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; -static const struct dmi_system_id touchscreen_dmi_tabl
[PATCH v2 1/5] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Signed-off-by: Hans de Goede --- Changes in v2: -Do not call pr_err on debugfs call failures --- arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 53 ++ 2 files changed, 57 insertions(+) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..0f968c7bcfec 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -374,6 +374,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index cd42f66a7c85..10c896e8b82b 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,55 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +static struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) + return; + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) + continue; + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -360,6 +410,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG)) + efi_debugfs_init(); + return 0; err_remove_group: -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 2/5] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware near the end of start_kernel(), just before calling rest_init(), this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(), so the check must be done after mm_init(). This relies on EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86 for now. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-fw" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set --- .../driver-api/firmware/request_firmware.rst | 70 + drivers/base/firmware_loader/main.c | 33 drivers/firmware/efi/Kconfig | 6 + drivers/firmware/efi/Makefile | 1 + drivers/firmware/efi/embedded-firmware.c | 148 ++ include/linux/efi.h | 6 + include/linux/efi_embedded_fw.h | 25 +++ init/main.c | 1 + 8 files changed, 290 insertions(+) create mode 100644 drivers/firmware/efi/embedded-firmware.c create mode 100644 include/linux/efi_embedded_fw.h diff --git a/Documentation/driver-api/firmware/request_firmware.rst b/Documentation/driver-api/firmware/request_firmware.rst index 20f21ed427a5..246d52211db7 100644 --- a/Documentation/driver-api/firmware/request_firmware.rst +++ b/Documentation/driver-api/firmware/request_firmware.rst @@ -68,3 +68,73 @@ If something went wrong request_firmware() returns non-zero and fw_entry is set to NULL. Once your driver is done with processing the firmware it can call call release_firmware(fw_entry) to release the firmware image and any related resource. + +EFI embedded firmware support += + +On some devices the system's EFI code / ROM may contain an embedded copy +of firmware for some of the system's integrated peripheral devices and +the peripheral's Linux device-driver needs to access this firmware. + +A device driver which needs this can describe the firmware it needs +using an efi_embedded_fw_desc struct: + +.. kernel-doc:: include/linux/efi_embedded_fw.h + :functions: efi_embedded_fw_desc + +The EFI embedded-fw code works by scanning all EFI_BOOT_SERVICES_CODE memory +segments for an eight byte sequence matching prefix, if the prefix is found it +then does a crc32 over length bytes and if that matches makes a copy of length +bytes and adds that to its list with found firmwares. + +To avoid doing this somewhat expensive scan on all systems, dmi matching is +used. Drivers are
[PATCH v2 3/5] platform/x86: Rename silead_dmi to touchscreen_dmi
Not only silead touchscreens need some extra info not available in the ACPI tables to work properly. X86 devices with a Chipone ICN8505 chip also need some DMI based extra configuration. There is no reason to have separate dmi config code per touchscreen controller vendor. This commit renames silead_dmi to a more generic touchscreen_dmi name (and Kconfig option) in preparation of adding info for tablets with an ICN8505 based touchscreen. Note there are no functional changes all code changes are limited to removing references to silead where these are no longer applicable. Signed-off-by: Hans de Goede --- MAINTAINERS | 2 +- drivers/platform/x86/Kconfig | 16 ++--- drivers/platform/x86/Makefile | 2 +- .../x86/{silead_dmi.c => touchscreen_dmi.c} | 66 +-- 4 files changed, 43 insertions(+), 43 deletions(-) rename drivers/platform/x86/{silead_dmi.c => touchscreen_dmi.c} (87%) diff --git a/MAINTAINERS b/MAINTAINERS index 0d5c55daeeba..99dd47e3b0dd 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -12618,7 +12618,7 @@ L: linux-in...@vger.kernel.org L: platform-driver-...@vger.kernel.org S: Maintained F: drivers/input/touchscreen/silead.c -F: drivers/platform/x86/silead_dmi.c +F: drivers/platform/x86/touchscreen_dmi.c SILICON MOTION SM712 FRAME BUFFER DRIVER M: Sudip Mukherjee diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index 1868aab0282a..b836576f0fe4 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1194,16 +1194,16 @@ config INTEL_TURBO_MAX_3 This driver is only required when the system is not using Hardware P-States (HWP). In HWP mode, priority can be read from ACPI tables. -config SILEAD_DMI - bool "Tablets with Silead touchscreens" +config TOUCHSCREEN_DMI + bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD ---help--- - Certain ACPI based tablets with Silead touchscreens do not have - enough data in ACPI tables for the touchscreen driver to handle - the touchscreen properly, as OEMs expected the data to be baked - into the tablet model specific version of the driver shipped - with the OS-image for the device. This option supplies the missing - information. Enable this for x86 tablets with Silead touchscreens. + Certain ACPI based tablets with e.g. Silead or Chipone touchscreens + do not have enough data in ACPI tables for the touchscreen driver to + handle the touchscreen properly, as OEMs expect the data to be baked + into the tablet model specific version of the driver shipped with the + the OS-image for the device. This option supplies the missing info. + Enable this for x86 tablets with Silead or Chipone touchscreens. config INTEL_CHTDC_TI_PWRBTN tristate "Intel Cherry Trail Dollar Cove TI power button driver" diff --git a/drivers/platform/x86/Makefile b/drivers/platform/x86/Makefile index 2ba6cb795338..8d9477114fb5 100644 --- a/drivers/platform/x86/Makefile +++ b/drivers/platform/x86/Makefile @@ -78,7 +78,7 @@ obj-$(CONFIG_INTEL_SMARTCONNECT) += intel-smartconnect.o obj-$(CONFIG_PVPANIC) += pvpanic.o obj-$(CONFIG_ALIENWARE_WMI)+= alienware-wmi.o obj-$(CONFIG_INTEL_PMC_IPC)+= intel_pmc_ipc.o -obj-$(CONFIG_SILEAD_DMI) += silead_dmi.o +obj-$(CONFIG_TOUCHSCREEN_DMI) += touchscreen_dmi.o obj-$(CONFIG_SURFACE_PRO3_BUTTON) += surfacepro3_button.o obj-$(CONFIG_SURFACE_3_BUTTON) += surface3_button.o obj-$(CONFIG_INTEL_PUNIT_IPC) += intel_punit_ipc.o diff --git a/drivers/platform/x86/silead_dmi.c b/drivers/platform/x86/touchscreen_dmi.c similarity index 87% rename from drivers/platform/x86/silead_dmi.c rename to drivers/platform/x86/touchscreen_dmi.c index 452aacabaa8e..87fc839b28f7 100644 --- a/drivers/platform/x86/silead_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -1,5 +1,5 @@ /* - * Silead touchscreen driver DMI based configuration code + * Touchscreen driver DMI based configuration code * * Copyright (c) 2017 Red Hat Inc. * @@ -20,7 +20,7 @@ #include #include -struct silead_ts_dmi_data { +struct ts_dmi_data { const char *acpi_name; const struct property_entry *properties; }; @@ -34,7 +34,7 @@ static const struct property_entry cube_iwork8_air_props[] = { { } }; -static const struct silead_ts_dmi_data cube_iwork8_air_data = { +static const struct ts_dmi_data cube_iwork8_air_data = { .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -48,7 +48,7 @@ static const struct property_entry jumper_ezpad_mini3_props[] = { { } }; -static const struct silead_ts_dmi_data jumper_ezpad_mini3_data = { +static c
[PATCH v2 5/5] platform/x86: touchscreen_dmi: Add info for the Chuwi Vi8 Plus tablet
Add touchscreen info for the Chuwi Vi8 Plus tablet. This tablet uses a Chipone ICN8505 touchscreen controller, with the firmware used by the touchscreen embedded in the EFI firmware. Signed-off-by: Hans de Goede --- drivers/platform/x86/touchscreen_dmi.c | 25 + 1 file changed, 25 insertions(+) diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 6488cd50ba79..5fdb6fe878f4 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -301,6 +301,22 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; +static const struct property_entry efi_embedded_fw_props[] = { + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), + { } +}; + +static const struct ts_dmi_data chuwi_vi8_plus_data = { + .embedded_fw = { + .name = "chipone/icn8505-HAMP0002.fw", + .prefix = { 0xb0, 0x07, 0x00, 0x00, 0xe4, 0x07, 0x00, 0x00 }, + .length = 35012, + .crc= 0x74dfd3fc, + }, + .acpi_name = "CHPN0001:00", + .properties = efi_embedded_fw_props, +}; + const struct dmi_system_id touchscreen_dmi_table[] = { { /* CUBE iwork8 Air */ @@ -487,6 +503,15 @@ const struct dmi_system_id touchscreen_dmi_table[] = { DMI_MATCH(DMI_PRODUCT_NAME, "Y8W81"), }, }, + { + /* Chuwi Vi8 Plus (CWI506) */ + .driver_data = (void *)&chuwi_vi8_plus_data, + .matches = { + DMI_MATCH(DMI_SYS_VENDOR, "Hampoo"), + DMI_MATCH(DMI_PRODUCT_NAME, "D2D3_Vi8A1"), + DMI_MATCH(DMI_BOARD_NAME, "Cherry Trail CR"), + }, + }, { }, }; -- 2.17.0 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH v2 4/5] platform/x86: touchscreen_dmi: Add EFI embedded firmware info support
Sofar we have been unable to get permission from the vendors to put the firmware for touchscreens listed in touchscreen_dmi in linux-firmware. Some of the tablets with such a touchscreen have a touchscreen driver, and thus a copy of the firmware, as part of their EFI code. This commit adds the necessary info for the new EFI embedded-firmware code to extract these firmwares, making the touchscreen work OOTB without the user needing to manually add the firmware. Signed-off-by: Hans de Goede --- drivers/firmware/efi/embedded-firmware.c | 3 +++ drivers/platform/x86/Kconfig | 1 + drivers/platform/x86/touchscreen_dmi.c | 26 +++- include/linux/efi_embedded_fw.h | 2 ++ 4 files changed, 31 insertions(+), 1 deletion(-) diff --git a/drivers/firmware/efi/embedded-firmware.c b/drivers/firmware/efi/embedded-firmware.c index cb57225a340d..26101ac1a282 100644 --- a/drivers/firmware/efi/embedded-firmware.c +++ b/drivers/firmware/efi/embedded-firmware.c @@ -23,6 +23,9 @@ struct embedded_fw { static LIST_HEAD(found_fw_list); static const struct dmi_system_id * const embedded_fw_table[] = { +#ifdef CONFIG_TOUCHSCREEN_DMI + touchscreen_dmi_table, +#endif NULL }; diff --git a/drivers/platform/x86/Kconfig b/drivers/platform/x86/Kconfig index b836576f0fe4..5bb0f5edd7f2 100644 --- a/drivers/platform/x86/Kconfig +++ b/drivers/platform/x86/Kconfig @@ -1197,6 +1197,7 @@ config INTEL_TURBO_MAX_3 config TOUCHSCREEN_DMI bool "DMI based touchscreen configuration info" depends on ACPI && DMI && I2C=y && TOUCHSCREEN_SILEAD + select EFI_EMBEDDED_FIRMWARE if EFI_STUB ---help--- Certain ACPI based tablets with e.g. Silead or Chipone touchscreens do not have enough data in ACPI tables for the touchscreen driver to diff --git a/drivers/platform/x86/touchscreen_dmi.c b/drivers/platform/x86/touchscreen_dmi.c index 87fc839b28f7..6488cd50ba79 100644 --- a/drivers/platform/x86/touchscreen_dmi.c +++ b/drivers/platform/x86/touchscreen_dmi.c @@ -15,12 +15,15 @@ #include #include #include +#include #include #include #include #include struct ts_dmi_data { + /* The EFI embedded-fw code expects this to be the first member! */ + struct efi_embedded_fw_desc embedded_fw; const char *acpi_name; const struct property_entry *properties; }; @@ -31,10 +34,17 @@ static const struct property_entry cube_iwork8_air_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3670-cube-iwork8-air.fw"), PROPERTY_ENTRY_U32("silead,max-fingers", 10), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data cube_iwork8_air_data = { + .embedded_fw = { + .name = "silead/gsl3670-cube-iwork8-air.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 38808, + .crc= 0xfecde51f, + }, .acpi_name = "MSSL1680:00", .properties = cube_iwork8_air_props, }; @@ -119,10 +129,17 @@ static const struct property_entry pipo_w2s_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl1680-pipo-w2s.fw"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data pipo_w2s_data = { + .embedded_fw = { + .name = "silead/gsl1680-pipo-w2s.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39072, + .crc= 0x28d5dc6c, + }, .acpi_name = "MSSL1680:00", .properties = pipo_w2s_props, }; @@ -162,10 +179,17 @@ static const struct property_entry chuwi_hi8_pro_props[] = { PROPERTY_ENTRY_BOOL("touchscreen-swapped-x-y"), PROPERTY_ENTRY_STRING("firmware-name", "gsl3680-chuwi-hi8-pro.fw"), PROPERTY_ENTRY_BOOL("silead,home-button"), + PROPERTY_ENTRY_BOOL("efi-embedded-firmware"), { } }; static const struct ts_dmi_data chuwi_hi8_pro_data = { + .embedded_fw = { + .name = "silead/gsl3680-chuwi-hi8-pro.fw", + .prefix = { 0xf0, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00 }, + .length = 39864, + .crc= 0xfe2bedba, + }, .acpi_name = "MSSL1680:00", .properties = chuwi_hi8_pro_props, }; @@ -277,7 +301,7 @@ static const struct ts_dmi_data teclast_x3_plus_data = { .properties = teclast_x3_plus_props, }; -static const struct dmi_system_id touchscreen_dmi_tabl
[PATCH v2 0/5] efi/firmware/platform-x86: Add EFI embedded fw support
Hi All, Here is v2 of my patch-set to add support for EFI embedded fw to the kernel. The 3 most prominent changes are: 1) Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst 2) Instead of having a single dmi_system_id array with its driver_data members pointing to efi_embedded_fw_desc structs, have the drivers which need EFI embedded-fw support export a dmi_system_id array and register that with the EFI embedded-fw code This series also includes the first driver to use this, in the form of the touchscreen_dmi code (formerly silead_dmi) from drivers/platfrom/x86 3) As discussed during the review of v1 we want to make the firmware_loader code fallback to EFI embedded-fw optional. Rather the adding yet another firmware_request_foo variant for this, with the risk of later also needing firmware_request_foo_nowait, etc. variants I've decided to make the code check if the device has a "efi-embedded-fw" device-property bool set. This also seemed better because the same driver may want to use the fallback on some systems, but not on others since e.g. not all (x86) systems with a silead touchscreen have their touchscreen firmware embedded in their EFI. Note that (as discussed) when the EFI fallback path is requested, the usermodehelper fallback path is skipped. Here is the full changelog of patch 2/5 which is where most of the changes are: Changes in v2: -Rebased on driver-core/driver-core-next -Add documentation describing the EFI embedded firmware mechanism to: Documentation/driver-api/firmware/request_firmware.rst -Add a new EFI_EMBEDDED_FIRMWARE Kconfig bool and only build the embedded fw support if this is set. This is an invisible option which should be selected by drivers which need this -Remove the efi_embedded_fw_desc and dmi_system_id-s for known devices from the efi-embedded-fw code, instead drivers using this are expected to export a dmi_system_id array, with each entries' driver_data pointing to a efi_embedded_fw_desc struct and register this with the efi-embedded-fw code -Use kmemdup to make a copy instead of efi_mem_reserve()-ing the firmware, this avoids us messing with the EFI memmap and avoids the need to make changes to efi_mem_desc_lookup() -Make the firmware-loader code only fallback to efi_get_embedded_fw() if the passed in device has the "efi-embedded-fw" device-property bool set -Skip usermodehelper fallback when "efi-embedded-firmware" device-property is set Patches 3-5 are new and implement using the EFI embedded-fw mechanism for Silead gsl and Chipone icn8505 touchscreens on x86 devices. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efi: Add embedded peripheral firmware support
Hi, On 06-04-18 16:08, Luis R. Rodriguez wrote: On Thu, Apr 05, 2018 at 07:43:49AM +0200, Lukas Wunner wrote: On Wed, Apr 04, 2018 at 01:18:36PM -0400, Peter Jones wrote: On Tue, Apr 03, 2018 at 08:07:11PM +0200, Lukas Wunner wrote: * Add the EFI Firmware Volume Protocol to include/linux/efi.h: https://www.intel.com/content/dam/doc/reference-guide/efi-firmware-file-volume-specification.pdf * Amend arch/x86/boot/compressed/eboot.c to read the files with the GUIDs you're interested in into memory and pass the files to the kernel as setup_data payloads. To be honest, I'm a bit skeptical about the firmware volume approach. Tools like UEFITool[0] and uefi-firmware-parser[1] have existed for years, still don't seem to reliably parse firmware images I see in the wild, and have a fairly regular need for fixes. These are tools maintained by smart people who are making a real effort, and it still looks pretty hard to do a good job that applies across a lot of platforms. So I'd rather use Hans's existing patches, at least for now, and if someone is interested in hacking on making an efi firmware volume parser for the kernel, switch them to that when such a thing is ready. Hello? As I've written in the above-quoted e-mail the kernel should read the files using EFI_FIRMWARE_VOLUME_PROTOCOL.ReadFile(). *Not* by parsing the firmware volume! Parsing the firmware volume is only necessary to find out the GUIDs of the files you're looking for. You only do that *once*. How do you get the GUIDs for each driver BTW? Hans, I do believe we should *try* this approach at the very least. Ok, so I've made a ROM dump of one of the tablets which I have with the touchscreen firmware embedded in the EFI code using flashrom, then I ran UEFIExtract on it, to get all the separate files. Then I wrote a little test.sh script using hexdump piped to grep to find the magic prefix, here is the result of running this on all files UEFIExtract generated: [hans@shalem chuwi-vi8-plus-cwi519-bios.bin.dump]$ find -type f -exec ./test.sh '{}' \; 0x0c403136B0 07 00 00 E4 07 00 00 found in ./2 BIOS region/6 8C8CE578-8A3D-4F1C-9935-896185C32DD3/31 I2cHid/1 EE4E5898-3914-4259-9D6E-DC7BD79403CF/0 PE32 image section/body.bin 0x0be03040B0 07 00 00 E4 07 00 00 found in ./2 BIOS region/5 8C8CE578-8A3D-4F1C-9935-896185C32DD3/31 I2cHid/1 EE4E5898-3914-4259-9D6E-DC7BD79403CF/0 PE32 image section/body.bin With the version found at offset 0xbe0 of the "5 8C8CE578-8A3D-4F1C-9935-896185C32DD3" section matching what we find in the efi_boot_services_code while running. As the I2cHid name suggests this is embedded in the driver (which is a PE executable), not in a separate file: [hans@shalem chuwi-vi8-plus-cwi519-bios.bin.dump]$ file './2 BIOS region/5 8C8CE578-8A3D-4F1C-9935-896185C32DD3/31 I2cHid/1 EE4E5898-3914-4259-9D6E-DC7BD79403CF/0 PE32 image section/body.bin' ./2 BIOS region/5 8C8CE578-8A3D-4F1C-9935-896185C32DD3/31 I2cHid/1 EE4E5898-3914-4259-9D6E-DC7BD79403CF/0 PE32 image section/body.bin: MS-DOS executable So using the EFI_FIRMWARE_VOLUME_PROTOCOL.ReadFile() is not really going to help here, since this is not in a separate file which we can consume in its entirety, we still need to scan for the prefix and do e.g. a CRC check to make sure we've actually got what we expect, at which point simply scanning all of efi_boot_services_code is a lot simpler and less error prone. Using an implementation specific EFI protocol for this means calling into EFI code and potentially triggering various bugs in there, breaking boot. This is esp. likely to happen since this is a protocol which is not used outside of the EFI ROMs internal code so there are likely little ABI guarantees making this approach extra error prone. Just scanning the efi_boot_services_code OTOH is quite safe TODO. As for the overhead of scanning the efi_boot_services_code, we are only doing this on a dmi match, so on most machines there is no overhead other then the dmi check. On machines where there is a dmi match, the price (I guess about 30 ms or so for the scan) is well worth the result of having the touchscreen OOTB. Regard, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efi: Add embedded peripheral firmware support
Hi, On 03-04-18 20:47, Luis R. Rodriguez wrote: In your next patches please Cc the folks I added for future review as well. We don't have a mailing list for the firmware API so I just tend to Cc who I think should help review when needed. Hmm, quite a long Cc list, but ok. On Tue, Apr 03, 2018 at 10:33:25AM +0200, Hans de Goede wrote: This is not part of the standard. There has been a long(ish) standing issue with us not being able to get re-distribute permission for the firmware for some touchscreen controllers found on cheap x86 devices. Which means that we cannot put it in Linux firmware. BTW do these cheap x86 devices have hw signing support? Not sure what you mean with hw signing support here, they support UEFI secure-boot and have a fTPM. Just curious thinking long term here. Because of it is not-standard then perhaps wen can partner later up with a vendor to this properly and actually support hw firmware singing. Dave Olsthoorn (in the Cc) noticed that the touchscreen did work in the refind bootload UI, so the EFI code must have a copy of the firmware. :) I asked Peter Jones for suggestions how to extract this during boot and he suggested seeing if there was a copy of the firmware in the EFI_BOOT_SERVICES_CODE memory segment, which it turns out there is. Sneaky Pete, nice. So essentially we're reverse engineering support for this. Yes. Anyway please mention that this is not part of standard in the documentation, and we've just found out in practice some vendors are doing this. That would avoid having people ask later. Ok, I will add some docs for v2 of the patch. My patch to add support for this contains a table of device-model (dmi strings), firmware header (first 64 bits), length and crc32 and then if we boot on a device-model which is in the table the code scans the EFI_BOOT_SERVICES_CODE for the prefix, if found checks the crc and caches the firmware for later use by request-firmware. Neat, best to add proper docs for this. Ok. So I just do a brute-force search for the firmware, this really is hack, nothing standard about it I'm afraid. But it works on 4 different x86 tablets I have and makes the touchscreen work OOTB on them, so I believe it is a worthwhile hack to have. Absolutely, just not to shove an entire fallback firmware path to all users. Ok. What mechanism would have in place to ensure that a driver which expects firmware to be on EFI data to be already available prior to its driver's call to initialize? See above, this still runs before start_kernel() calls rest_init() which is where any normal init calls (and driver probing) happens so still early enough for any users I can think of. The firmware API is even used to load microcode, but that relies on built-in firmware support. That code needs to be refactored to be a proper citizen of the firmware API, right now its just a hack. Reason for asking all these details was to ensure we document the restrictions correctly so that expecations are set correctly for callers prior to rest_init(). Please be sure to document the limitations. Ok. This means we rely on the EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86, if we ever want this on ARM we should make ARM delay the freeing of the EFI_BOOT_SERVICES_* memory-segments too. Why not do that as well with your patch? That requires making significant changes to the early bringup code on ARM, x86 keeps EFI_BOOT_SERVICES_* memory-segments around until near the end of start_kernel() because freeing them earlier triggers bugs in some x86 EFI implementations, ARM EFI implementations do not have these bugs, so they free them almost directly at boot. Changing this really falls outside the scope of this patch. Sure but did you poke ARM folks about it? Maybe they can do it? And if this becomes a common practice, perhaps they can do it with actual firmware signing instead of a CRC. Not sure how hard it is to exploit EFI_BOOT_SERVICES_CODE... but it may help UEFI folks with a nice warm fuzzy to start doing this right later instead of propagating what seems to be a cheap hack. If things are compromised before the kernel boots no amount of checks are going to help us, an attacker can then just boot an entirely different kernel, rather then attacking the system through a backdoored firmware, so a CRC should be fine. Either way I'm happy to switch to a crypto hash, but the crypto subsystem is not initialized yet at this point AFAICT, so using a CRC is easier. Note this commit also modifies efi_mem_desc_lookup() to not skip EFI_BOOT_SERVICES_CODE memory-segments, so that efi_mem_reserve() works on such segments. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- drivers/base/firmware_class.c| 29 +++ drivers/firmware/efi/Makefile| 1 + drivers/firmware
Re: [PATCH 2/2] efi: Add embedded peripheral firmware support
Hi, On 03-04-18 21:53, Peter Jones wrote: On Sat, Mar 31, 2018 at 02:19:44PM +0200, Hans de Goede wrote: diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index fddc5f706fd2..1a5ea950f58f 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -455,6 +455,7 @@ int __init efi_mem_desc_lookup(u64 phys_addr, efi_memory_desc_t *out_md) u64 end; if (!(md->attribute & EFI_MEMORY_RUNTIME) && + md->type != EFI_BOOT_SERVICES_CODE && md->type != EFI_BOOT_SERVICES_DATA && md->type != EFI_RUNTIME_SERVICES_DATA) { continue; Might be worth adding a comment here to ensure nobody comes along later and adds something like EFI_BOOT_LOADER_DATA or other stuff that's allocated later here. I don't want to accidentally patch our way into having the ability to stumble across a firmware blob somebody dumped into the middle of a grub config file, especially since you only need to collide crc32 (within the same length) to pre-alias a match. As discussed elsewhere in the thread, I'm going to switch to doing a kmemdup on the found firmware, so this chunk will go away :) ... +static int __init efi_check_md_for_embedded_firmware( + efi_memory_desc_t *md, const struct embedded_fw_desc *desc) +{ ... + if (found_fw_count >= MAX_EMBEDDED_FIRMWARES) { + pr_err("Error already have %d embedded firmwares\n", + MAX_EMBEDDED_FIRMWARES); + return -ENOSPC; + } Doesn't seem like this needs to be pr_err(); after all we have already found a valid match, so the firmware vendor has done something moderately stupid, but we have a firmware that will probably work. Of course it still needs to return != 0, but pr_warn() or even pr_info() seems more reasonable. We break from the search loop as soon as a firmware is found, this can only trigger if someone adds a second firmware to the dmi data and then does not update MAX_EMBEDDED_FIRMWARES... But mcgrof wants me to switch to a linked list here, so this is going away too. Aside from those nits, looks good to me. Reviewed-by: Peter Jones Thanks, but v2 is going to have so much changes that I don't feel comfortable bringing this forward to v2. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efi: Add embedded peripheral firmware support
HI, On 04-04-18 19:18, Peter Jones wrote: On Tue, Apr 03, 2018 at 06:58:48PM +, Luis R. Rodriguez wrote: On Tue, Apr 03, 2018 at 08:07:11PM +0200, Lukas Wunner wrote: On Tue, Apr 03, 2018 at 10:33:25AM +0200, Hans de Goede wrote: I asked Peter Jones for suggestions how to extract this during boot and he suggested seeing if there was a copy of the firmware in the EFI_BOOT_SERVICES_CODE memory segment, which it turns out there is. My patch to add support for this contains a table of device-model (dmi strings), firmware header (first 64 bits), length and crc32 and then if we boot on a device-model which is in the table the code scans the EFI_BOOT_SERVICES_CODE for the prefix, if found checks the crc and caches the firmware for later use by request-firmware. So I just do a brute-force search for the firmware, this really is hack, nothing standard about it I'm afraid. But it works on 4 different x86 tablets I have and makes the touchscreen work OOTB on them, so I believe it is a worthwhile hack to have. The EFI Firmware Volume contains a kind of filesystem with files identified by GUIDs. Those files include EFI drivers, ACPI tables, DMI data and so on. It is actually quite common for vendors to also include device firmware on the Firmware Volume. Apple is doing this to ship firmware updates e.g. for the GMUX controller found on dual GPU MacBook Pros. If they want to update the controller's firmware, they include it in a BIOS update, and an EFI driver checks on boot if the firmware update for the controller is necessary and if so, flashes it. The firmware files you're looking for are almost certainly included on the Firmware Volume as individual files. What Hans implemented seems to have been for a specific x86 hack, best if we confirm if indeed they are present on the Firmware Volume. To be honest, I'm a bit skeptical about the firmware volume approach. Tools like UEFITool[0] and uefi-firmware-parser[1] have existed for years, still don't seem to reliably parse firmware images I see in the wild, and have a fairly regular need for fixes. These are tools maintained by smart people who are making a real effort, and it still looks pretty hard to do a good job that applies across a lot of platforms. So I'd rather use Hans's existing patches, at least for now, and if someone is interested in hacking on making an efi firmware volume parser for the kernel, switch them to that when such a thing is ready. [0] g...@github.com:LongSoft/UEFITool.git [1] g...@github.com:theopolis/uefi-firmware-parser.git Rather than scraping the EFI memory for firmware, I think it would be cleaner and more elegant if you just retrieve the files you're interested in from the Firmware Volume. We're doing something similar with Apple EFI properties, see 58c5475aba67 and c9cc3aaa0281. Basically what you need to do to implement this approach is: * Determine the GUIDs used by vendors for the files you're interested in. Either dump the Firmware Volume or take an EFI update as shipped by the vendor, then feed it to UEFIExtract: https://github.com/LongSoft/UEFITool * Add the EFI Firmware Volume Protocol to include/linux/efi.h: https://www.intel.com/content/dam/doc/reference-guide/efi-firmware-file-volume-specification.pdf * Amend arch/x86/boot/compressed/eboot.c to read the files with the GUIDs you're interested in into memory and pass the files to the kernel as setup_data payloads. * Once the kernel has booted, make the files you've retrieved available to device drivers as firmware blobs. Happen to know if devices using Firmware Volumes also sign their firmware and if hw checks the firmware at load time? It varies on a per-device basis, of course. Most new Intel machines as of Haswell *should* be verifying their system firmware via Boot Guard, which both checks an RSA signature and measures the firmware into the TPM, but as with everything of this nature, there are certainly vendors that screw it up. (I think AMD has something similar, but I'm really not sure.) Lukas, thank you for your suggestions on this, but I doubt that these devices use the Firmware Volume stuff. These are really cheap x86 Windows 10 tablets, everything about them is simply hacked together by the manufacturer till it boots Windows10 and then it is shipped to the customer without receiving any update afterwards ever. What you are describing sounds like significantly more work then the vendor just embedding the firmware as a char firmware[] in their EFI mouse driver. That combined with Peter's worries about difficulties parsing the Firmware Volume stuff, makes me believe that it is best to just stick with my current approach as Peter suggests. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: [PATCH 2/2] efi: Add embedded peripheral firmware support
Hi Luis, Thank you for the review. On 03-04-18 01:23, Luis R. Rodriguez wrote: On Sat, Mar 31, 2018 at 02:19:44PM +0200, Hans de Goede wrote: Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. Some devices have OTP and use this sort of calibration data, Right, I'm not sure it really is OTP and not flash, but many touchscreen controllers do come with their firmware embedded into the controller, but not all unfortunately. I was unaware of the use of EFI to stash firmware. Good to know, but can you also provide references to what part of what standard should be followed for it in documentation? This is not part of the standard. There has been a long(ish) standing issue with us not being able to get re-distribute permission for the firmware for some touchscreen controllers found on cheap x86 devices. Which means that we cannot put it in Linux firmware. Dave Olsthoorn (in the Cc) noticed that the touchscreen did work in the refind bootload UI, so the EFI code must have a copy of the firmware. I asked Peter Jones for suggestions how to extract this during boot and he suggested seeing if there was a copy of the firmware in the EFI_BOOT_SERVICES_CODE memory segment, which it turns out there is. My patch to add support for this contains a table of device-model (dmi strings), firmware header (first 64 bits), length and crc32 and then if we boot on a device-model which is in the table the code scans the EFI_BOOT_SERVICES_CODE for the prefix, if found checks the crc and caches the firmware for later use by request-firmware. So I just do a brute-force search for the firmware, this really is hack, nothing standard about it I'm afraid. But it works on 4 different x86 tablets I have and makes the touchscreen work OOTB on them, so I believe it is a worthwhile hack to have. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Neat. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware pretty late in the init sequence, This also creates a technical limitation on use for the API that users should be aware of. Its important to document such limitation. I don't think this is a problem for any normal drivers, when I say pretty late I mean late in init/main.c: start_kernel(), so still before any normal drivers load. The first idea was to scan for the firmware at the same time we check for things as the ACPI BGRT logo stuff, but as mentioned that requires using early_mmap() which does not work for the amount of memory we want to map. Also if we can address the limitation that would be even better. For instance, on what part of the driver is the call to request firmware being made? Note that we support async probe now, so if the call was done on probe, it may be wise to use async probe, however, can we be *certain* that the EFI firmware would have been parsed and ready by then? Please check. It just may be the case. Or, if we use late_initcall() would that suffice on the driver, if they used a request firmware call on init or probe? As said I think we still do it early enough for any driver use, when I wrote "late in the init sequence" I should have probably written something else, like "near the end of start_kernel() instead of from setup_arch()" this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(). To be clear you neede to use memremap() Yes. What mechanism would have in place to ensure that a driver which expects firmware to be on EFI data to be already available prior to its driver's call to initialize? See above, this still runs before start_kernel() calls rest_init() which is where any normal init calls (and driver probing) happens so still early enough for any users I can think of. I think my p
Re: [PATCH 1/2] efi: Export boot-services code and data as debugfs-blobs
Hi, On 03/31/2018 04:10 PM, Greg Kroah-Hartman wrote: On Sat, Mar 31, 2018 at 02:19:43PM +0200, Hans de Goede wrote: Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Signed-off-by: Hans de Goede --- arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 57 ++ 2 files changed, 61 insertions(+) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..0f968c7bcfec 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -374,6 +374,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index cd42f66a7c85..fddc5f706fd2 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,59 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) { + pr_warn("Could not create efi debugfs entry\n"); + return; + } {sigh} No, don't warn, or complain, or do anything else if a debugfs call fails. Just keep on moving, you can always use the return value properly in any future call if you need it, and no code flow should ever care if a debugfs call succeeded or failed. Ok. /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -360,6 +414,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG)) + efi_debugfs_init(); You never remove the directory? Correct, this is happening from a subsys_initcall as such there is no efi_cleanup() counterpart. Note the "if (efi_enabled(EFI_DBG))" check checks for efi=debug on the kernel cmdline, so this only happens if the user asked for it. Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH 2/2] efi: Add embedded peripheral firmware support
Just like with PCI options ROMs, which we save in the setup_efi_pci* functions from arch/x86/boot/compressed/eboot.c, the EFI code / ROM itself sometimes may contain data which is useful/necessary for peripheral drivers to have access to. Specifically the EFI code may contain an embedded copy of firmware which needs to be (re)loaded into the peripheral. Normally such firmware would be part of linux-firmware, but in some cases this is not feasible, for 2 reasons: 1) The firmware is customized for a specific use-case of the chipset / use with a specific hardware model, so we cannot have a single firmware file for the chipset. E.g. touchscreen controller firmwares are compiled specifically for the hardware model they are used with, as they are calibrated for a specific model digitizer. 2) Despite repeated attempts we have failed to get permission to redistribute the firmware. This is especially a problem with customized firmwares, these get created by the chip vendor for a specific ODM and the copyright may partially belong with the ODM, so the chip vendor cannot give a blanket permission to distribute these. This commit adds support for finding peripheral firmware embedded in the EFI code and making this available to peripheral drivers through the standard firmware loading mechanism. Note we check the EFI_BOOT_SERVICES_CODE for embedded firmware pretty late in the init sequence, this is on purpose because the typical EFI_BOOT_SERVICES_CODE memory-segment is too large for early_memremap(). This means we rely on the EFI_BOOT_SERVICES_CODE not being free-ed until efi_free_boot_services() is called, which means that this will only work on x86, if we ever want this on ARM we should make ARM delay the freeing of the EFI_BOOT_SERVICES_* memory-segments too. Note this commit also modifies efi_mem_desc_lookup() to not skip EFI_BOOT_SERVICES_CODE memory-segments, so that efi_mem_reserve() works on such segments. Reported-by: Dave Olsthoorn Suggested-by: Peter Jones Signed-off-by: Hans de Goede --- drivers/base/firmware_class.c| 29 +++ drivers/firmware/efi/Makefile| 1 + drivers/firmware/efi/efi.c | 1 + drivers/firmware/efi/embedded-firmware.c | 232 +++ include/linux/efi.h | 2 + init/main.c | 1 + 6 files changed, 266 insertions(+) create mode 100644 drivers/firmware/efi/embedded-firmware.c diff --git a/drivers/base/firmware_class.c b/drivers/base/firmware_class.c index 7dd36ace6152..b1e7b3de1975 100644 --- a/drivers/base/firmware_class.c +++ b/drivers/base/firmware_class.c @@ -12,6 +12,7 @@ #include #include +#include #include #include #include @@ -1207,6 +1208,32 @@ static inline void unregister_sysfs_loader(void) #endif /* CONFIG_FW_LOADER_USER_HELPER */ +#ifdef CONFIG_EFI +static int +fw_get_efi_embedded_fw(struct device *dev, struct fw_priv *fw_priv, int ret) +{ + size_t size; + int rc; + + rc = efi_get_embedded_fw(fw_priv->fw_name, &fw_priv->data, &size, +fw_priv->data ? fw_priv->allocated_size : 0); + if (rc == 0) { + dev_dbg(dev, "using efi-embedded fw %s\n", fw_priv->fw_name); + fw_priv->size = size; + fw_state_done(fw_priv); + ret = 0; + } + + return ret; +} +#else +static inline int +fw_get_efi_embedded_fw(struct device *dev, struct fw_priv *fw_priv, int ret) +{ + return ret; +} +#endif + /* prepare firmware and firmware_buf structs; * return 0 if a firmware is already assigned, 1 if need to load one, * or a negative error code @@ -1296,6 +1323,8 @@ _request_firmware(const struct firmware **firmware_p, const char *name, goto out; ret = fw_get_filesystem_firmware(device, fw->priv); + if (ret) + ret = fw_get_efi_embedded_fw(device, fw->priv, ret); if (ret) { if (!(opt_flags & FW_OPT_NO_WARN)) dev_warn(device, diff --git a/drivers/firmware/efi/Makefile b/drivers/firmware/efi/Makefile index cb805374f4bc..cb946f7d0181 100644 --- a/drivers/firmware/efi/Makefile +++ b/drivers/firmware/efi/Makefile @@ -13,6 +13,7 @@ KASAN_SANITIZE_runtime-wrappers.o := n obj-$(CONFIG_ACPI_BGRT)+= efi-bgrt.o obj-$(CONFIG_EFI) += efi.o vars.o reboot.o memattr.o tpm.o obj-$(CONFIG_EFI) += capsule.o memmap.o +obj-$(CONFIG_EFI) += embedded-firmware.o obj-$(CONFIG_EFI_VARS) += efivars.o obj-$(CONFIG_EFI_ESRT) += esrt.o obj-$(CONFIG_EFI_VARS_PSTORE) += efi-pstore.o diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index fddc5f706fd2..1a5ea950f58f 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -455,6 +455,7 @@ int __init efi_mem_desc_lo
[PATCH 1/2] efi: Export boot-services code and data as debugfs-blobs
Sometimes it is useful to be able to dump the efi boot-services code and data. This commit adds these as debugfs-blobs to /sys/kernel/debug/efi, but only if efi=debug is passed on the kernel-commandline as this requires not freeing those memory-regions, which costs 20+ MB of RAM. Signed-off-by: Hans de Goede --- arch/x86/platform/efi/quirks.c | 4 +++ drivers/firmware/efi/efi.c | 57 ++ 2 files changed, 61 insertions(+) diff --git a/arch/x86/platform/efi/quirks.c b/arch/x86/platform/efi/quirks.c index 5b513ccffde4..0f968c7bcfec 100644 --- a/arch/x86/platform/efi/quirks.c +++ b/arch/x86/platform/efi/quirks.c @@ -374,6 +374,10 @@ void __init efi_free_boot_services(void) int num_entries = 0; void *new, *new_md; + /* Keep all regions for /sys/kernel/debug/efi */ + if (efi_enabled(EFI_DBG)) + return; + for_each_efi_memory_desc(md) { unsigned long long start = md->phys_addr; unsigned long long size = md->num_pages << EFI_PAGE_SHIFT; diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c index cd42f66a7c85..fddc5f706fd2 100644 --- a/drivers/firmware/efi/efi.c +++ b/drivers/firmware/efi/efi.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -316,6 +317,59 @@ static __init int efivar_ssdt_load(void) static inline int efivar_ssdt_load(void) { return 0; } #endif +#ifdef CONFIG_DEBUG_FS + +#define EFI_DEBUGFS_MAX_BLOBS 32 + +struct debugfs_blob_wrapper debugfs_blob[EFI_DEBUGFS_MAX_BLOBS]; + +static void __init efi_debugfs_init(void) +{ + struct dentry *efi_debugfs; + efi_memory_desc_t *md; + char name[32]; + int type_count[EFI_BOOT_SERVICES_DATA + 1] = {}; + int i = 0; + + efi_debugfs = debugfs_create_dir("efi", NULL); + if (IS_ERR_OR_NULL(efi_debugfs)) { + pr_warn("Could not create efi debugfs entry\n"); + return; + } + + for_each_efi_memory_desc(md) { + switch (md->type) { + case EFI_BOOT_SERVICES_CODE: + snprintf(name, sizeof(name), "boot_services_code%d", +type_count[md->type]++); + break; + case EFI_BOOT_SERVICES_DATA: + snprintf(name, sizeof(name), "boot_services_data%d", +type_count[md->type]++); + break; + default: + continue; + } + + debugfs_blob[i].size = md->num_pages << EFI_PAGE_SHIFT; + debugfs_blob[i].data = memremap(md->phys_addr, + debugfs_blob[i].size, + MEMREMAP_WB); + if (!debugfs_blob[i].data) { + pr_warn("Error mapping %s\n", name); + continue; + } + + debugfs_create_blob(name, 0400, efi_debugfs, &debugfs_blob[i]); + i++; + if (i == EFI_DEBUGFS_MAX_BLOBS) + break; + } +} +#else +static inline void efi_debugfs_init(void) {} +#endif + /* * We register the efi subsystem with the firmware subsystem and the * efivars subsystem with the efi subsystem, if the system was booted with @@ -360,6 +414,9 @@ static int __init efisubsys_init(void) goto err_remove_group; } + if (efi_enabled(EFI_DBG)) + efi_debugfs_init(); + return 0; err_remove_group: -- 2.17.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
[PATCH] efi: Ignore unrealistically large option roms
setup_efi_pci() tries to save a copy of each PCI option ROM as this may be necessary for the device driver for the PCI device to have access too. On some systems the efi_pci_io_protocol_64's romimage and romsize fields contain invalid data, which looks a bit like pointers pointing back into other EFI code or data. Interpreting these pointers as romsize leads to a very large value and if we then try to alloc this amount of memory to save a copy the alloc call fails. This leads to a "Failed to alloc mem for rom" error being printed on the EFI console for each PCI device. This commit avoids the printing of these errors, by checking romsize before doing the alloc and if it is larger then 256M silently ignore the ROM fields instead of trying to alloc mem and fail. Signed-off-by: Hans de Goede --- arch/x86/boot/compressed/eboot.c | 8 +++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/arch/x86/boot/compressed/eboot.c b/arch/x86/boot/compressed/eboot.c index 886a9115af62..f744b037d3cd 100644 --- a/arch/x86/boot/compressed/eboot.c +++ b/arch/x86/boot/compressed/eboot.c @@ -230,7 +230,13 @@ __setup_efi_pci64(efi_pci_io_protocol_64 *pci, struct pci_setup_rom **__rom) if (status != EFI_SUCCESS) return status; - if (!pci->romimage || !pci->romsize) + /* +* Some firmwares contain EFI function pointers at the place where the +* romimage and romsize fields are supposed to be. Typically the EFI +* code is mapped at high addresses, translating to an unrealistically +* large romsize. We reject any roms over 256M in size to catch this. +*/ + if (!pci->romimage || !pci->romsize || pci->romsize > 0x1000) return EFI_INVALID_PARAMETER; size = pci->romsize + sizeof(*rom); -- 2.17.0.rc2 -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Regression from efi: call get_event_log before ExitBootServices
Hi, On 12-03-18 22:02, Ard Biesheuvel wrote: On 12 March 2018 at 19:55, Thiebaud Weksteen wrote: On Mon, Mar 12, 2018 at 7:33 PM Jeremy Cline wrote: On 03/12/2018 02:29 PM, Thiebaud Weksteen wrote: On Mon, Mar 12, 2018 at 6:30 PM Ard Biesheuvel < ard.biesheu...@linaro.org> wrote: On 12 March 2018 at 17:01, Jeremy Cline wrote: On 03/12/2018 10:56 AM, Ard Biesheuvel wrote: On 12 March 2018 at 14:30, Jeremy Cline wrote: On 03/12/2018 07:08 AM, Ard Biesheuvel wrote: On 10 March 2018 at 10:45, Thiebaud Weksteen wrote: On Fri, Mar 9, 2018 at 5:54 PM Jeremy Cline wrote: On Fri, Mar 09, 2018 at 10:43:50AM +, Thiebaud Weksteen wrote: Thanks a lot for trying out the patch! Please don't modify your install at this stage, I think we are hitting a firmware bug and that would be awesome if we can fix how we are handling it. So, if we reach that stage in the function it could either be that: * The allocation did not succeed, somehow, but the firmware still returned EFI_SUCCEED. * The size requested is incorrect (I'm thinking something like a 1G of log). This would be due to either a miscalculation of log_size (possible) or; the returned values of GetEventLog are not correct. I'm sending a patch to add checks for these. Could you please apply and retest? Again, thanks for helping debugging this. No problem, thanks for the help :) With the new patch: Locating the TCG2Protocol Calling GetEventLog on TCG2Protocol Log returned log_location is not empty log_size != 0 log_size < 1M Allocating memory for storing the logs Returned from memory allocation Copying log to new location And then it hangs. I added a couple more print statements: diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index ee3fac109078..1ab5638bc50e 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -148,8 +148,11 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_printk(sys_table_arg, "Copying log to new location\n"); memset(log_tbl, 0, sizeof(*log_tbl) + log_size); + efi_printk(sys_table_arg, "Successfully memset log_tbl to 0\n"); log_tbl->size = log_size; + efi_printk(sys_table_arg, "Set log_tbl->size\n"); log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + efi_printk(sys_table_arg, "Set log_tbl-version\n"); memcpy(log_tbl->log, (void *) first_entry_addr, log_size); efi_printk(sys_table_arg, "Installing the log into the configuration table\n"); and it's hanging at "memset(log_tbl, 0, sizeof(*log_tbl) + log_size);" Thanks. Well, it looks like the memory that is supposedly allocated is not usable. I'm thinking this is a firmware bug. Ard, would you agree on this assumption? Thoughts on how to proceed? I am rather puzzled why the allocate_pool() should succeed and the subsequent memset() should fail. This does not look like an issue that is intimately related to TPM2 support, rather an issue in the firmware that happens to get tickled after the change. Would you mind trying replacing EFI_LOADER_DATA with EFI_BOOT_SERVICES_DATA in the allocate_pool() call? Replacing EFI_LOADER_DATA with EFI_BOOT_SERVICES_DATA still hangs at the memset() call. Could you try the following please? (attached as well in case gmail mangles it) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 2298560cea72..30d960a344b7 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -70,6 +70,8 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) size_t log_size, last_entry_size; efi_bool_t truncated; void *tcg2_protocol; + unsigned long num_pages; + efi_physical_addr_t log_tbl_alloc; status = efi_call_early(locate_protocol, &tcg2_guid, NULL, &tcg2_protocol); @@ -104,9 +106,12 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) } /* Allocate space for the logs and copy them. */ - status = efi_call_early(allocate_pool, EFI_LOADER_DATA, - sizeof(*log_tbl) + log_size, - (void **) &log_tbl); + num_pages = DIV_ROUND_UP(sizeof(*log_tbl) + log_size, EFI_PAGE_SIZE); + status = efi_call_early(allocate_pages, + EFI_ALLOCATE_ANY_PAGES, + EFI_LOADER_DATA, + num_pages, + &log_tbl_alloc); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, @@ -114,6 +119,7 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) return; } + log_tbl = (struct linux_efi_tpm_eventlog *)(unsigned long)log_tbl_alloc; memset(log_tbl, 0, si
Re: Regression from efi: call get_event_log before ExitBootServices
Hi, On 12-03-18 20:55, Thiebaud Weksteen wrote: On Mon, Mar 12, 2018 at 7:33 PM Jeremy Cline wrote: On 03/12/2018 02:29 PM, Thiebaud Weksteen wrote: On Mon, Mar 12, 2018 at 6:30 PM Ard Biesheuvel < ard.biesheu...@linaro.org> wrote: On 12 March 2018 at 17:01, Jeremy Cline wrote: On 03/12/2018 10:56 AM, Ard Biesheuvel wrote: On 12 March 2018 at 14:30, Jeremy Cline wrote: On 03/12/2018 07:08 AM, Ard Biesheuvel wrote: On 10 March 2018 at 10:45, Thiebaud Weksteen wrote: On Fri, Mar 9, 2018 at 5:54 PM Jeremy Cline wrote: On Fri, Mar 09, 2018 at 10:43:50AM +, Thiebaud Weksteen wrote: Thanks a lot for trying out the patch! Please don't modify your install at this stage, I think we are hitting a firmware bug and that would be awesome if we can fix how we are handling it. So, if we reach that stage in the function it could either be that: * The allocation did not succeed, somehow, but the firmware still returned EFI_SUCCEED. * The size requested is incorrect (I'm thinking something like a 1G of log). This would be due to either a miscalculation of log_size (possible) or; the returned values of GetEventLog are not correct. I'm sending a patch to add checks for these. Could you please apply and retest? Again, thanks for helping debugging this. No problem, thanks for the help :) With the new patch: Locating the TCG2Protocol Calling GetEventLog on TCG2Protocol Log returned log_location is not empty log_size != 0 log_size < 1M Allocating memory for storing the logs Returned from memory allocation Copying log to new location And then it hangs. I added a couple more print statements: diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index ee3fac109078..1ab5638bc50e 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -148,8 +148,11 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) efi_printk(sys_table_arg, "Copying log to new location\n"); memset(log_tbl, 0, sizeof(*log_tbl) + log_size); + efi_printk(sys_table_arg, "Successfully memset log_tbl to 0\n"); log_tbl->size = log_size; + efi_printk(sys_table_arg, "Set log_tbl->size\n"); log_tbl->version = EFI_TCG2_EVENT_LOG_FORMAT_TCG_1_2; + efi_printk(sys_table_arg, "Set log_tbl-version\n"); memcpy(log_tbl->log, (void *) first_entry_addr, log_size); efi_printk(sys_table_arg, "Installing the log into the configuration table\n"); and it's hanging at "memset(log_tbl, 0, sizeof(*log_tbl) + log_size);" Thanks. Well, it looks like the memory that is supposedly allocated is not usable. I'm thinking this is a firmware bug. Ard, would you agree on this assumption? Thoughts on how to proceed? I am rather puzzled why the allocate_pool() should succeed and the subsequent memset() should fail. This does not look like an issue that is intimately related to TPM2 support, rather an issue in the firmware that happens to get tickled after the change. Would you mind trying replacing EFI_LOADER_DATA with EFI_BOOT_SERVICES_DATA in the allocate_pool() call? Replacing EFI_LOADER_DATA with EFI_BOOT_SERVICES_DATA still hangs at the memset() call. Could you try the following please? (attached as well in case gmail mangles it) diff --git a/drivers/firmware/efi/libstub/tpm.c b/drivers/firmware/efi/libstub/tpm.c index 2298560cea72..30d960a344b7 100644 --- a/drivers/firmware/efi/libstub/tpm.c +++ b/drivers/firmware/efi/libstub/tpm.c @@ -70,6 +70,8 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) size_t log_size, last_entry_size; efi_bool_t truncated; void *tcg2_protocol; + unsigned long num_pages; + efi_physical_addr_t log_tbl_alloc; status = efi_call_early(locate_protocol, &tcg2_guid, NULL, &tcg2_protocol); @@ -104,9 +106,12 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) } /* Allocate space for the logs and copy them. */ - status = efi_call_early(allocate_pool, EFI_LOADER_DATA, - sizeof(*log_tbl) + log_size, - (void **) &log_tbl); + num_pages = DIV_ROUND_UP(sizeof(*log_tbl) + log_size, EFI_PAGE_SIZE); + status = efi_call_early(allocate_pages, + EFI_ALLOCATE_ANY_PAGES, + EFI_LOADER_DATA, + num_pages, + &log_tbl_alloc); if (status != EFI_SUCCESS) { efi_printk(sys_table_arg, @@ -114,6 +119,7 @@ void efi_retrieve_tpm2_eventlog_1_2(efi_system_table_t *sys_table_arg) return; } + log_tbl = (struct linux_efi_tpm_eventlog *)(unsigned long)log_tbl_alloc; memset(log_tbl, 0, sizeof(*log_tbl) + log_size); log_tbl->size
Re: Regression from efi: call get_event_log before ExitBootServices
Hi, On 08-03-18 18:26, Jeremy Cline wrote: On 03/08/2018 11:50 AM, Hans de Goede wrote: Hi, On 07-03-18 12:34, Javier Martinez Canillas wrote: Are you also able to read the TPM event logs? $ hexdump /sys/kernel/security/tpm0/binary_bios_measurements Yes for me that outputs a lot of hex :) For me, /sys/kernel/security/tmp0 doesn't exist on 4.15.6 or 4.16 with the patch reverted. Hmm, have you re-enabled the TPM in the BIOS? The UEFI firmware does some measurements and so does shim. So you should have some event logs. What version of shim are you using? And also would be good to know if it's the same shim version that Jeremy is using. That is a very good question, I'm using: shim-ia32-13-0.7.x86_64, which is the last version for F27 AFAICT. All my tablet has installed is shim-0.8-10.x86_64, no shim-ia32. Yes my bad, although if the kernel changes break booting on systems without the shim that is still good to know and something which we probably ought to fix. But Jeremy's tablet might very well be not using the shim at all, as I manually installed Fedora 25 on the tablet he now has, before Fedora supported machines with 32 bit EFI. I then later did a "dnf distro-sync" to Fedora-27. Jeremy might also very well still be booting using a grub binary I build manually back then, without any shim being involved. Jeremy what does efibootmgr -v output on your device ? # efibootmgr -v BootCurrent: 0003 Timeout: 4 seconds BootOrder: 0003,,0001,2001,2002,2003 Boot* Android X64 OS HD(1,GPT,215e6cf3-e97d-4735-9c4e-7338c8f5a645,0x800,0x32000)/File(\EFI\BOOT\bootx64.efi)RC Boot0001* Internal EFI Shell FvVol(a881d567-6cb0-4eee-8435-2e72d33e45b5)/FvFile(c57ad6b7-0515-40a8-9d21-551652854e37)RCM&". Boot0003* Fedora HD(1,GPT,215e6cf3-e97d-4735-9c4e-7338c8f5a645,0x800,0x32000)/File(\EFI\fedora\grubx64.efi) Boot2001* EFI USB DeviceRC Boot2002* EFI DVD/CDROM RC Boot2003* EFI Network RC Boot8087* Udm FvVol(a881d567-6cb0-4eee-8435-2e72d33e45b5)/FvFile(9a9ab4c1-ee1b-488b-b300-24544a7bd418) I think you're right about it using the old grub binary. I'm embarrassingly unfamiliar with both UEFI and grub, but I'm guessing you set the location of grub.cfg at compile time? When I boot \EFI\fedora\grubx64.efi, it's pulling the grub.cfg from \EFI\redhat\grub.cfg. Ah yes, so I did not build my own grub I took one from RHEL as that had 32 bit UEFI support before Fedora got it and as I was lazy I copied the 32 bit binary over the 64 bit one, so don't let the filename fool you. What you could do is install grub2-efi-ia32 from the Fedora 27 repos and then use efibootmgr to add an entry pointing to \EFI\fedora\grubia32.efi note that one will look at \EFI\fedora\grub.cfg . Then see if the problem persists. A second step would be to also install shim-ia32 and point to that... Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Regression from efi: call get_event_log before ExitBootServices
Hi, On 07-03-18 12:34, Javier Martinez Canillas wrote: On 03/07/2018 12:10 PM, Hans de Goede wrote: Both according to the BIOS and to the /sys/class/tpm/tpm0/device/description file it is a TPM 2.0. I see, so you can choose enabling the TPM 1.2 or TPM 2.0 device? At least that's the case on my X1 Carbon laptop. I've both a hardware TPM 1.2 and a firmware TPM 2.0 that's implemented as an Intel ME application (AFAIU). This device only has the firmware TPM 2.0 implementation. I'm actually amazed that this machine has a TPM at all, a quick internet search shows that it is a software implemented TPM running as part of the TXE firmware. A quick search suggests that it comes with Windows 10? Yes, it comes with Windows 10. For start, can you please check if you can boot a v4.16-rcX kernel with the TPM device enabled? That way we will know that at least that it consistently fails on this machine and is not and isolated issue. I just tried and v4.16-rc3 boots fine for me, repeatedly. That's an interesting data point. I guess Jeremy's model may actually have something in the TPM log I don't think so. The UEFI firmware already does some measurements and also does shim. So you *should* have some logs. while my TPM log is empty... Is there anyway to make sure the TPM log has some info to retreive? Are you also able to read the TPM event logs? $ hexdump /sys/kernel/security/tpm0/binary_bios_measurements Yes for me that outputs a lot of hex :) The UEFI firmware does some measurements and so does shim. So you should have some event logs. What version of shim are you using? And also would be good to know if it's the same shim version that Jeremy is using. That is a very good question, I'm using: shim-ia32-13-0.7.x86_64, which is the last version for F27 AFAICT. But Jeremy's tablet might very well be not using the shim at all, as I manually installed Fedora 25 on the tablet he now has, before Fedora supported machines with 32 bit EFI. I then later did a "dnf distro-sync" to Fedora-27. Jeremy might also very well still be booting using a grub binary I build manually back then, without any shim being involved. Jeremy what does efibootmgr -v output on your device ? Regards, Hans -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html
Re: Regression from efi: call get_event_log before ExitBootServices
Hi, On 07-03-18 09:41, Thiebaud Weksteen wrote: Hi, Thanks for testing and sending this report! This patch relies heavily on the functions exposed by the firmware. My first guess would be that some of these may not be implemented correctly by the manufacturer. Could you share more information on this specific device? I've the same device as Jeremy, but I just tried a 4.16-rc3 kernel and I'm not seeing this problem, BIOS settings all default (I loaded the BIOS defaults to make sure). Do you have any link to the manufacturer website (I found [1] but it is based on an ARM CPU)? Do you have the option to update your firmware? Is a copy of the firmware available from the manufacturer? This is a really cheap Windows tablet which was given away for free in the Netherlands with some home-schooling language courses, or something similar. Both mine and Jeremy tablets come from a website in the Netherlands where people can buy/sell used goods. Most relevant for this discussion I guess is that this device is based on a Bay Trail Z3735G SoC, on which according to the internets: https://embedded.communities.intel.com/thread/7868 The TPM 2.0 it contains is implemented as part of the TXE firmware. Since I cannot reproduce I'm thinking that maybe Jeremy actually has some log messages in the TPM log, where as mine is empty. Is there a way to make sure some messages are in there? Regards, Hans On your side, I assume no error message got displayed on the screen when booting. Would you be able to try to boot in an UEFI shell [2] and execute the command "dh -v"? Thanks, Thiebaud [1] https://www.gp-electronic.nl/product/7inchtablet [2] https://wiki.archlinux.org/index.php/Unified_Extensible_Firmware_Interface#UEFI_Shell On Tue, Mar 6, 2018 at 5:00 PM Jeremy Cline wrote: Hi folks, Commit 33b6d03469b2 ("efi: call get_event_log before ExitBootServices") causes my GP-electronic T701 tablet to hang when booting. Reverting the patch series or hiding the TPM in the BIOS fixes the problem. I've never fiddled with TPMs before so I'm not sure what what debugging information to provide. It's got an Atom Z3735G and the UEFI firmware is InsydeH20 version BYT70A.YNCHENG.WIN.007. Regards, Jeremy -- To unsubscribe from this list: send the line "unsubscribe linux-efi" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html