[U-Boot] [RFC 1/1] efi_loader: refactor switch to hypervisor mode

Mark Kettenis mark.kettenis at xs4all.nl
Tue Dec 25 12:39:08 UTC 2018


> From: Heinrich Schuchardt <xypron.glpk at gmx.de>
> Date: Tue, 25 Dec 2018 09:26:57 +0100
> 
> Refactor the switch from supervisor to hypervisor to a new function called at
> the beginning of do_bootefi().
> 
> Signed-off-by: Heinrich Schuchardt <xypron.glpk at gmx.de>
> ---
> With this patch I am just moving around the switch from supervisor to
> hypervisor mode within the EFI subsystem. Similar switching also occurs
> in all other boot commands (cf. arch/arm/lib/bootm.c).

Never been a huge fan of setjmp/longjmp, but I can see what you're
doing here.  This is tricky code though, so I think this needs to be
tested on armv7 systems that support virtualisation (Cortex-A7) and
systems that don't (Cortex-A9).

> Why are we running the U-Boot console in supervisor mode at all? Wouldn't
> it be advisable for security reasons to switch to hypervisor mode before
> entering the console?

On some boards there are commands that access secure devices.  So
those commands would no longer work.  Obviously that is already the
case when an EFI payload returns to the U-Boot command prompt.

> ---
>  cmd/bootefi.c | 109 ++++++++++++++++++++++----------------------------
>  1 file changed, 47 insertions(+), 62 deletions(-)
> 
> diff --git a/cmd/bootefi.c b/cmd/bootefi.c
> index 1aaf5319e13..277d4863953 100644
> --- a/cmd/bootefi.c
> +++ b/cmd/bootefi.c
> @@ -31,9 +31,9 @@ DECLARE_GLOBAL_DATA_PTR;
>  #define OBJ_LIST_NOT_INITIALIZED 1
>  
>  static efi_status_t efi_obj_list_initialized = OBJ_LIST_NOT_INITIALIZED;
> -
>  static struct efi_device_path *bootefi_image_path;
>  static struct efi_device_path *bootefi_device_path;
> +struct jmp_buf_data hyp_jmp;
>  
>  /* Initialize and populate EFI object list */
>  efi_status_t efi_init_obj_list(void)
> @@ -122,6 +122,50 @@ void __weak allow_unaligned(void)
>  {
>  }
>  
> +/**
> + * entry_hyp() - entry point when switching to hypervisor mode
> + */
> +static void entry_hyp(void)
> +{
> +	dcache_enable();
> +	debug("Reached HYP mode\n");
> +	longjmp(&hyp_jmp, 1);
> +}
> +
> +/**
> + * leave_supervisor() - switch to hypervisor mode
> + */
> +static void leave_supervisor(void)
> +{
> +#ifdef CONFIG_ARMV7_NONSEC
> +	static bool is_nonsec;
> +
> +	if (armv7_boot_nonsec() && !is_nonsec) {
> +		if (setjmp(&hyp_jmp))
> +			return;
> +		dcache_disable();	/* flush cache before switch to HYP */
> +		armv7_init_nonsec();
> +		is_nonsec = true;
> +		secure_ram_addr(_do_nonsec_entry)(entry_hyp, 0, 0, 0);
> +	}
> +#endif
> +
> +#ifdef CONFIG_ARM64
> +	/* On AArch64 we need to make sure we call our payload in < EL3 */
> +	if (current_el() == 3) {
> +		if (setjmp(&hyp_jmp))
> +			return;
> +		smp_kick_all_cpus();
> +		dcache_disable();	/* flush cache before switch to EL2 */
> +
> +		/* Move into EL2 and keep running there */
> +		armv8_switch_to_el2(0, 0, 0, 0, (uintptr_t)entry_hyp,
> +				    ES_TO_AARCH64);
> +	}
> +#endif
> +	return;
> +}
> +
>  /*
>   * Set the load options of an image from an environment variable.
>   *
> @@ -233,34 +277,6 @@ static efi_status_t efi_do_enter(
>  	return ret;
>  }
>  
> -#ifdef CONFIG_ARM64
> -static efi_status_t efi_run_in_el2(EFIAPI efi_status_t (*entry)(
> -			efi_handle_t image_handle, struct efi_system_table *st),
> -			efi_handle_t image_handle, struct efi_system_table *st)
> -{
> -	/* Enable caches again */
> -	dcache_enable();
> -
> -	return efi_do_enter(image_handle, st, entry);
> -}
> -#endif
> -
> -#ifdef CONFIG_ARMV7_NONSEC
> -static bool is_nonsec;
> -
> -static efi_status_t efi_run_in_hyp(EFIAPI efi_status_t (*entry)(
> -			efi_handle_t image_handle, struct efi_system_table *st),
> -			efi_handle_t image_handle, struct efi_system_table *st)
> -{
> -	/* Enable caches again */
> -	dcache_enable();
> -
> -	is_nonsec = true;
> -
> -	return efi_do_enter(image_handle, st, entry);
> -}
> -#endif
> -
>  /*
>   * efi_carve_out_dt_rsv() - Carve out DT reserved memory ranges
>   *
> @@ -440,39 +456,6 @@ static efi_status_t do_bootefi_exec(void *efi,
>  		goto err_prepare;
>  	}
>  
> -#ifdef CONFIG_ARM64
> -	/* On AArch64 we need to make sure we call our payload in < EL3 */
> -	if (current_el() == 3) {
> -		smp_kick_all_cpus();
> -		dcache_disable();	/* flush cache before switch to EL2 */
> -
> -		/* Move into EL2 and keep running there */
> -		armv8_switch_to_el2((ulong)entry,
> -				    (ulong)&image_obj->header,
> -				    (ulong)&systab, 0, (ulong)efi_run_in_el2,
> -				    ES_TO_AARCH64);
> -
> -		/* Should never reach here, efi exits with longjmp */
> -		while (1) { }
> -	}
> -#endif
> -
> -#ifdef CONFIG_ARMV7_NONSEC
> -	if (armv7_boot_nonsec() && !is_nonsec) {
> -		dcache_disable();	/* flush cache before switch to HYP */
> -
> -		armv7_init_nonsec();
> -		secure_ram_addr(_do_nonsec_entry)(
> -					efi_run_in_hyp,
> -					(uintptr_t)entry,
> -					(uintptr_t)&image_obj->header,
> -					(uintptr_t)&systab);
> -
> -		/* Should never reach here, efi exits with longjmp */
> -		while (1) { }
> -	}
> -#endif
> -
>  	ret = efi_do_enter(&image_obj->header, &systab, entry);
>  
>  err_prepare:
> @@ -558,6 +541,8 @@ static int do_bootefi(cmd_tbl_t *cmdtp, int flag, int argc, char * const argv[])
>  	/* Allow unaligned memory access */
>  	allow_unaligned();
>  
> +	leave_supervisor();
> +
>  	/* Initialize EFI drivers */
>  	r = efi_init_obj_list();
>  	if (r != EFI_SUCCESS) {
> -- 
> 2.19.2
> 
> _______________________________________________
> U-Boot mailing list
> U-Boot at lists.denx.de
> https://lists.denx.de/listinfo/u-boot


More information about the U-Boot mailing list