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/