Re: [PATCH] x86: serialize EFI time accesses on rtc_lock

From: Rakib Mullick
Date: Tue Jul 19 2011 - 13:32:11 EST


On Tue, Jul 19, 2011 at 4:53 PM, Jan Beulich <JBeulich@xxxxxxxxxx> wrote:
> The EFI specification requires that callers of the time related runtime
> functions serialize with other CMOS accesses in the kernel, as the EFI
> time functions may choose to also use the legacy CMOS RTC.
>
> Besides fixing a latent bug, this is a prerequisite to safely enable
> the rtc-efi driver for x86, which ought to be preferred over rtc-cmos
> on all EFI platforms.
>
> Signed-off-by: Jan Beulich <jbeulich@xxxxxxxxxx>
> Cc: Matthew Garrett <mjg@xxxxxxxxxx>
>
> ---
>  arch/x86/platform/efi/efi.c |   39 +++++++++++++++++++++++++++++++++------
>  1 file changed, 33 insertions(+), 6 deletions(-)
>
> --- 3.0-rc7/arch/x86/platform/efi/efi.c
> +++ 3.0-rc7-x86-rtc-lock-EFI/arch/x86/platform/efi/efi.c
> @@ -79,26 +79,50 @@ early_param("add_efi_memmap", setup_add_
>
>  static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc)
>  {
> -       return efi_call_virt2(get_time, tm, tc);
> +       unsigned long flags;
> +       efi_status_t status;
> +
> +       spin_lock_irqsave(&rtc_lock, flags);
> +       status = efi_call_virt2(get_time, tm, tc);
> +       spin_unlock_irqrestore(&rtc_lock, flags);
> +       return status;
>  }
>
>  static efi_status_t virt_efi_set_time(efi_time_t *tm)
>  {
> -       return efi_call_virt1(set_time, tm);
> +       unsigned long flags;
> +       efi_status_t status;
> +
> +       spin_lock_irqsave(&rtc_lock, flags);
> +       status = efi_call_virt1(set_time, tm);
> +       spin_unlock_irqrestore(&rtc_lock, flags);
> +       return status;
>  }
>
>  static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
>                                             efi_bool_t *pending,
>                                             efi_time_t *tm)
>  {
> -       return efi_call_virt3(get_wakeup_time,
> -                             enabled, pending, tm);
> +       unsigned long flags;
> +       efi_status_t status;
> +
> +       spin_lock_irqsave(&rtc_lock, flags);
> +       status = efi_call_virt3(get_wakeup_time,
> +                               enabled, pending, tm);
> +       spin_unlock_irqrestore(&rtc_lock, flags);
> +       return status;
>  }
>
>  static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
>  {
> -       return efi_call_virt2(set_wakeup_time,
> -                             enabled, tm);
> +       unsigned long flags;
> +       efi_status_t status;
> +
> +       spin_lock_irqsave(&rtc_lock, flags);
> +       status = efi_call_virt2(set_wakeup_time,
> +                               enabled, tm);
> +       spin_unlock_irqrestore(&rtc_lock, flags);
> +       return status;
>  }
>
>  static efi_status_t virt_efi_get_variable(efi_char16_t *name,
> @@ -164,11 +188,14 @@ static efi_status_t __init phys_efi_set_
>  static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
>                                             efi_time_cap_t *tc)
>  {
> +       unsigned long flags;
>        efi_status_t status;
>
> +       spin_lock_irqsave(&rtc_lock, flags);
>        efi_call_phys_prelog();
>        status = efi_call_phys2(efi_phys.get_time, tm, tc);
>        efi_call_phys_epilog();
> +       spin_unlock_irqrestore(&rtc_lock, flags);
>        return status;
>  }
>
If I'm not missing anything, this implementation (serialization) could
be simpler by holding rtc_lock at the time of calling those functions.
I mean, holding rtc_lock before calling EFI services
virt_efi_get/set_time and virt_efi_get/set_wakeup_time - something
like below:

spin_lock_irqsave(&rtc_lock, flags);
efi.get_time = virt_efi_get_time;
efi.set_time = virt_efi_set_time;
efi.get_wakeup_time = virt_efi_get_wakeup_time;
efi.set_wakeup_time = virt_efi_set_wakeup_time;
spin_unlock_irqrestore(&rtc_lock, flags);


Thanks,
Rakib
>
>
>
> --
> To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
> the body of a message to majordomo@xxxxxxxxxxxxxxx
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> Please read the FAQ at  http://www.tux.org/lkml/
>
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/