diff --git a/src/basic/efivars.c b/src/basic/efivars.c index 5aeddef7e2..8e8d5f1d0b 100644 --- a/src/basic/efivars.c +++ b/src/basic/efivars.c @@ -290,8 +290,11 @@ bool is_efi_boot(void) { if (cache < 0) { if (detect_container() > 0) cache = false; - else + else { cache = access("/sys/firmware/efi/", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/efi/ exists, assuming EFI not available: %m"); + } } return cache; diff --git a/src/boot/bootctl.c b/src/boot/bootctl.c index 7b759bcd02..cccd834cc8 100644 --- a/src/boot/bootctl.c +++ b/src/boot/bootctl.c @@ -1233,6 +1233,7 @@ static int verb_status(int argc, char *argv[], void *userdata) { printf(" Firmware: %s%s (%s)%s\n", ansi_highlight(), strna(fw_type), strna(fw_info), ansi_normal()); printf(" Secure Boot: %sd\n", enable_disable(is_efi_secure_boot())); printf(" Setup Mode: %s\n", is_efi_secure_boot_setup_mode() ? "setup" : "user"); + printf(" TPM2 Support: %s\n", yes_no(efi_has_tpm2())); k = efi_get_reboot_to_firmware(); if (k > 0) diff --git a/src/shared/condition.c b/src/shared/condition.c index 8b00697762..485b3bab39 100644 --- a/src/shared/condition.c +++ b/src/shared/condition.c @@ -487,6 +487,17 @@ static int has_tpm2(void) { * class device */ r = dir_is_empty("/sys/class/tpmrm"); + if (r == 0) + return true; /* nice! we have a device */ + + /* Hmm, so Linux doesn't know of the TPM2 device (or we couldn't check for it), most likely because + * the driver wasn't loaded yet. Let's see if the firmware knows about a TPM2 device, in this + * case. This way we can answer the TPM2 question already during early boot (where we most likely + * need it) */ + if (efi_has_tpm2()) + return true; + + /* OK, this didn't work either, in this case propagate the original errors */ if (r == -ENOENT) return false; if (r < 0) diff --git a/src/shared/efi-loader.c b/src/shared/efi-loader.c index 20f70da31a..2aab39c32d 100644 --- a/src/shared/efi-loader.c +++ b/src/shared/efi-loader.c @@ -783,6 +783,29 @@ int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat return 0; } +bool efi_has_tpm2(void) { + static int cache = -1; + + /* Returns whether the system has a TPM2 chip which is known to the EFI firmware. */ + + if (cache < 0) { + + /* First, check if we are on an EFI boot at all. */ + if (!is_efi_boot()) + cache = false; + else { + /* Then, check if the ACPI table "TPM2" exists, which is the TPM2 event log table, see: + * https://trustedcomputinggroup.org/wp-content/uploads/TCG_ACPIGeneralSpecification_v1.20_r8.pdf + * This table exists whenever the firmware is hooked up to TPM2. */ + cache = access("/sys/firmware/acpi/tables/TPM2", F_OK) >= 0; + if (!cache && errno != ENOENT) + log_debug_errno(errno, "Unable to test whether /sys/firmware/acpi/tables/TPM2 exists, assuming it doesn't: %m"); + } + } + + return cache; +} + #endif bool efi_loader_entry_name_valid(const char *s) { diff --git a/src/shared/efi-loader.h b/src/shared/efi-loader.h index 7621794736..bc5769bb6b 100644 --- a/src/shared/efi-loader.h +++ b/src/shared/efi-loader.h @@ -29,6 +29,8 @@ int efi_loader_get_features(uint64_t *ret); int efi_loader_get_config_timeout_one_shot(usec_t *ret); int efi_loader_update_entry_one_shot_cache(char **cache, struct stat *cache_stat); +bool efi_has_tpm2(void); + #else static inline int efi_reboot_to_firmware_supported(void) { @@ -91,6 +93,10 @@ static inline int efi_loader_update_entry_one_shot_cache(char **cache, struct st return -EOPNOTSUPP; } +static inline bool efi_has_tpm2(void) { + return false; +} + #endif bool efi_loader_entry_name_valid(const char *s);