Skip to content
Snippets Groups Projects
Commit ef68c8f8 authored by Jan Beulich's avatar Jan Beulich Committed by Ingo Molnar
Browse files

x86: Serialize EFI time accesses on rtc_lock


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: default avatarJan Beulich <jbeulich@novell.com>
Acked-by: default avatarMatthew Garrett <mjg59@srcf.ucam.org>
Cc: <mjg@redhat.com>
Link: http://lkml.kernel.org/r/4E257E33020000780004E319@nat28.tlf.novell.com


Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
Cc: Matthew Garrett <mjg@redhat.com>
parent ac619f4e
No related branches found
No related tags found
No related merge requests found
...@@ -79,26 +79,50 @@ early_param("add_efi_memmap", setup_add_efi_memmap); ...@@ -79,26 +79,50 @@ early_param("add_efi_memmap", setup_add_efi_memmap);
static efi_status_t virt_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) 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) 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, static efi_status_t virt_efi_get_wakeup_time(efi_bool_t *enabled,
efi_bool_t *pending, efi_bool_t *pending,
efi_time_t *tm) efi_time_t *tm)
{ {
return efi_call_virt3(get_wakeup_time, unsigned long flags;
enabled, pending, tm); 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) static efi_status_t virt_efi_set_wakeup_time(efi_bool_t enabled, efi_time_t *tm)
{ {
return efi_call_virt2(set_wakeup_time, unsigned long flags;
enabled, tm); 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, static efi_status_t virt_efi_get_variable(efi_char16_t *name,
...@@ -164,11 +188,14 @@ static efi_status_t __init phys_efi_set_virtual_address_map( ...@@ -164,11 +188,14 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
static efi_status_t __init phys_efi_get_time(efi_time_t *tm, static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
efi_time_cap_t *tc) efi_time_cap_t *tc)
{ {
unsigned long flags;
efi_status_t status; efi_status_t status;
spin_lock_irqsave(&rtc_lock, flags);
efi_call_phys_prelog(); efi_call_phys_prelog();
status = efi_call_phys2(efi_phys.get_time, tm, tc); status = efi_call_phys2(efi_phys.get_time, tm, tc);
efi_call_phys_epilog(); efi_call_phys_epilog();
spin_unlock_irqrestore(&rtc_lock, flags);
return status; return status;
} }
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment