Re: [PATCH v3] efi/libstub: arm: Print CPU boot mode and MMU state at boot

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Tue, 16 Jun 2020 at 10:50, Ard Biesheuvel <ardb@xxxxxxxxxx> wrote:
>
> On 32-bit ARM, we may boot at HYP mode, or with the MMU and caches off
> (or both), even though the EFI spec does not actually support this.
> While booting at HYP mode is something we might tolerate, fiddling
> with the caches is a more serious issue, as disabling the caches is
> tricky to do safely from C code, and running without the Dcache makes
> it impossible to support unaligned memory accesses, which is another
> explicit requirement imposed by the EFI spec.
>
> So take note of the CPU mode and MMU state in the EFI stub diagnostic
> output so that we can easily diagnose any issues that may arise from
> this. E.g.,
>
>   EFI stub: Entering in SVC mode with MMU enabled
>
> Also, capture the CPSR and SCTLR system register values at EFI stub
> entry, and after ExitBootServices() returns, and check whether the
> MMU and Dcache were disabled at any point. If this is the case, a
> diagnostic message like the following will be emitted:
>
>   efi: [Firmware Bug]: EFI stub was entered with MMU and Dcache disabled, please fix your firmware!
>   efi: CPSR at EFI stub entry        : 0x600001d3
>   efi: SCTLR at EFI stub entry       : 0x00c51838
>   efi: CPSR after ExitBootServices() : 0x600001d3
>   efi: SCTLR after ExitBootServices(): 0x00c50838
>
> Signed-off-by: Ard Biesheuvel <ardb@xxxxxxxxxx>
> ---
> Adding Grant and Samer to cc, as this may be something that should be taken
> into account in the EBBR context? Note that this affects 64-bit only.
>

Affects *32* bit only


>  arch/arm/include/asm/efi.h                |  7 +++
>  drivers/firmware/efi/arm-init.c           | 37 ++++++++++++--
>  drivers/firmware/efi/libstub/arm32-stub.c | 52 +++++++++++++++++++-
>  drivers/firmware/efi/libstub/efi-stub.c   |  3 ++
>  drivers/firmware/efi/libstub/efistub.h    |  2 +
>  include/linux/efi.h                       |  1 +
>  6 files changed, 98 insertions(+), 4 deletions(-)
>
> diff --git a/arch/arm/include/asm/efi.h b/arch/arm/include/asm/efi.h
> index 84dc0ba822f5..5dcf3c6011b7 100644
> --- a/arch/arm/include/asm/efi.h
> +++ b/arch/arm/include/asm/efi.h
> @@ -87,4 +87,11 @@ static inline unsigned long efi_get_max_initrd_addr(unsigned long dram_base,
>         return dram_base + SZ_512M;
>  }
>
> +struct efi_arm_entry_state {
> +       u32     cpsr_before_ebs;
> +       u32     sctlr_before_ebs;
> +       u32     cpsr_after_ebs;
> +       u32     sctlr_after_ebs;
> +};
> +
>  #endif /* _ASM_ARM_EFI_H */
> diff --git a/drivers/firmware/efi/arm-init.c b/drivers/firmware/efi/arm-init.c
> index c697e70ca7e7..4d1c272a4f79 100644
> --- a/drivers/firmware/efi/arm-init.c
> +++ b/drivers/firmware/efi/arm-init.c
> @@ -52,9 +52,11 @@ static phys_addr_t __init efi_to_phys(unsigned long addr)
>  }
>
>  static __initdata unsigned long screen_info_table = EFI_INVALID_TABLE_ADDR;
> +static __initdata unsigned long cpu_state_table = EFI_INVALID_TABLE_ADDR;
>
>  static const efi_config_table_type_t arch_tables[] __initconst = {
>         {LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID, &screen_info_table},
> +       {LINUX_EFI_ARM_CPU_STATE_TABLE_GUID, &cpu_state_table},
>         {}
>  };
>
> @@ -116,7 +118,8 @@ static int __init uefi_init(u64 efi_system_table)
>                 goto out;
>         }
>         retval = efi_config_parse_tables(config_tables, systab->nr_tables,
> -                                        arch_tables);
> +                                        IS_ENABLED(CONFIG_ARM) ? arch_tables
> +                                                               : NULL);
>
>         early_memunmap(config_tables, table_size);
>  out:
> @@ -238,9 +241,37 @@ void __init efi_init(void)
>
>         init_screen_info();
>
> +#ifdef CONFIG_ARM
>         /* ARM does not permit early mappings to persist across paging_init() */
> -       if (IS_ENABLED(CONFIG_ARM))
> -               efi_memmap_unmap();
> +       efi_memmap_unmap();
> +
> +       if (cpu_state_table != EFI_INVALID_TABLE_ADDR) {
> +               struct efi_arm_entry_state *state;
> +               bool dump_state = true;
> +
> +               state = early_memremap_ro(cpu_state_table,
> +                                         sizeof(struct efi_arm_entry_state));
> +               if (state == NULL) {
> +                       pr_warn("Unable to map CPU entry state table.\n");
> +                       return;
> +               }
> +
> +               if ((state->sctlr_before_ebs & 1) == 0)
> +                       pr_warn(FW_BUG "EFI stub was entered with MMU and Dcache disabled, please fix your firmware!\n");
> +               else if ((state->sctlr_after_ebs & 1) == 0)
> +                       pr_warn(FW_BUG "ExitBootServices() returned with MMU and Dcache disabled, please fix your firmware!\n");
> +               else
> +                       dump_state = false;
> +
> +               if (dump_state || efi_enabled(EFI_DBG)) {
> +                       pr_info("CPSR at EFI stub entry        : 0x%08x\n", state->cpsr_before_ebs);
> +                       pr_info("SCTLR at EFI stub entry       : 0x%08x\n", state->sctlr_before_ebs);
> +                       pr_info("CPSR after ExitBootServices() : 0x%08x\n", state->cpsr_after_ebs);
> +                       pr_info("SCTLR after ExitBootServices(): 0x%08x\n", state->sctlr_after_ebs);
> +               }
> +               early_memunmap(state, sizeof(struct efi_arm_entry_state));
> +       }
> +#endif
>  }
>
>  static bool efifb_overlaps_pci_range(const struct of_pci_range *range)
> diff --git a/drivers/firmware/efi/libstub/arm32-stub.c b/drivers/firmware/efi/libstub/arm32-stub.c
> index 40243f524556..60783228db6e 100644
> --- a/drivers/firmware/efi/libstub/arm32-stub.c
> +++ b/drivers/firmware/efi/libstub/arm32-stub.c
> @@ -7,10 +7,49 @@
>
>  #include "efistub.h"
>
> +static efi_guid_t cpu_state_guid = LINUX_EFI_ARM_CPU_STATE_TABLE_GUID;
> +
> +struct efi_arm_entry_state *efi_entry_state;
> +
> +static void get_cpu_state(u32 *cpsr, u32 *sctlr)
> +{
> +       asm("mrs %0, cpsr" : "=r"(*cpsr));
> +       if ((*cpsr & MODE_MASK) == HYP_MODE)
> +               asm("mrc p15, 4, %0, c1, c0, 0" : "=r"(*sctlr));
> +       else
> +               asm("mrc p15, 0, %0, c1, c0, 0" : "=r"(*sctlr));
> +}
> +
>  efi_status_t check_platform_features(void)
>  {
> +       efi_status_t status;
> +       u32 cpsr, sctlr;
>         int block;
>
> +       get_cpu_state(&cpsr, &sctlr);
> +
> +       efi_info("Entering in %s mode with MMU %sabled\n",
> +                ((cpsr & MODE_MASK) == HYP_MODE) ? "HYP" : "SVC",
> +                (sctlr & 1) ? "en" : "dis");
> +
> +       status = efi_bs_call(allocate_pool, EFI_LOADER_DATA,
> +                            sizeof(*efi_entry_state),
> +                            (void **)&efi_entry_state);
> +       if (status != EFI_SUCCESS) {
> +               efi_err("allocate_pool() failed\n");
> +               return status;
> +       }
> +
> +       efi_entry_state->cpsr_before_ebs = cpsr;
> +       efi_entry_state->sctlr_before_ebs = sctlr;
> +
> +       status = efi_bs_call(install_configuration_table, &cpu_state_guid,
> +                            efi_entry_state);
> +       if (status != EFI_SUCCESS) {
> +               efi_err("install_configuration_table() failed\n");
> +               goto free_state;
> +       }
> +
>         /* non-LPAE kernels can run anywhere */
>         if (!IS_ENABLED(CONFIG_ARM_LPAE))
>                 return EFI_SUCCESS;
> @@ -19,9 +58,20 @@ efi_status_t check_platform_features(void)
>         block = cpuid_feature_extract(CPUID_EXT_MMFR0, 0);
>         if (block < 5) {
>                 efi_err("This LPAE kernel is not supported by your CPU\n");
> -               return EFI_UNSUPPORTED;
> +               status = EFI_UNSUPPORTED;
> +               goto free_state;
>         }
>         return EFI_SUCCESS;
> +
> +free_state:
> +       efi_bs_call(free_pool, efi_entry_state);
> +       return status;
> +}
> +
> +void efi_handle_post_ebs_state(void)
> +{
> +       get_cpu_state(&efi_entry_state->cpsr_after_ebs,
> +                     &efi_entry_state->sctlr_after_ebs);
>  }
>
>  static efi_guid_t screen_info_guid = LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID;
> diff --git a/drivers/firmware/efi/libstub/efi-stub.c b/drivers/firmware/efi/libstub/efi-stub.c
> index e97370bdfdb0..3318ec3f8e5b 100644
> --- a/drivers/firmware/efi/libstub/efi-stub.c
> +++ b/drivers/firmware/efi/libstub/efi-stub.c
> @@ -329,6 +329,9 @@ efi_status_t __efiapi efi_pe_entry(efi_handle_t handle,
>         if (status != EFI_SUCCESS)
>                 goto fail_free_initrd;
>
> +       if (IS_ENABLED(CONFIG_ARM))
> +               efi_handle_post_ebs_state();
> +
>         efi_enter_kernel(image_addr, fdt_addr, fdt_totalsize((void *)fdt_addr));
>         /* not reached */
>
> diff --git a/drivers/firmware/efi/libstub/efistub.h b/drivers/firmware/efi/libstub/efistub.h
> index bcd8c0a785f0..6217ce647ebf 100644
> --- a/drivers/firmware/efi/libstub/efistub.h
> +++ b/drivers/firmware/efi/libstub/efistub.h
> @@ -771,4 +771,6 @@ efi_status_t efi_load_initrd(efi_loaded_image_t *image,
>                              unsigned long soft_limit,
>                              unsigned long hard_limit);
>
> +void efi_handle_post_ebs_state(void);
> +
>  #endif
> diff --git a/include/linux/efi.h b/include/linux/efi.h
> index c3449c9699d0..bb35f3305e55 100644
> --- a/include/linux/efi.h
> +++ b/include/linux/efi.h
> @@ -350,6 +350,7 @@ void efi_native_runtime_setup(void);
>   * associated with ConOut
>   */
>  #define LINUX_EFI_ARM_SCREEN_INFO_TABLE_GUID   EFI_GUID(0xe03fc20a, 0x85dc, 0x406e,  0xb9, 0x0e, 0x4a, 0xb5, 0x02, 0x37, 0x1d, 0x95)
> +#define LINUX_EFI_ARM_CPU_STATE_TABLE_GUID     EFI_GUID(0xef79e4aa, 0x3c3d, 0x4989,  0xb9, 0x02, 0x07, 0xa9, 0x43, 0xe5, 0x50, 0xd2)
>  #define LINUX_EFI_LOADER_ENTRY_GUID            EFI_GUID(0x4a67b082, 0x0a4c, 0x41cf,  0xb6, 0xc7, 0x44, 0x0b, 0x29, 0xbb, 0x8c, 0x4f)
>  #define LINUX_EFI_RANDOM_SEED_TABLE_GUID       EFI_GUID(0x1ce1e5bc, 0x7ceb, 0x42f2,  0x81, 0xe5, 0x8a, 0xad, 0xf1, 0x80, 0xf5, 0x7b)
>  #define LINUX_EFI_TPM_EVENT_LOG_GUID           EFI_GUID(0xb7799cb0, 0xeca2, 0x4943,  0x96, 0x67, 0x1f, 0xae, 0x07, 0xb7, 0x47, 0xfa)
> --
> 2.27.0
>



[Index of Archives]     [Linux ARM Kernel]     [Linux ARM]     [Linux Omap]     [Fedora ARM]     [IETF Annouce]     [Security]     [Bugtraq]     [Linux OMAP]     [Linux MIPS]     [ECOS]     [Asterisk Internet PBX]     [Linux API]

  Powered by Linux