Skip to contentSkip to conversation

x86/efi: use GFP_ATOMIC under spin_lock

PATCH In review Dan Carpenter 6 participants 24 messages Mar 7, 2014 – Mar 14, 2014 7 messages not in the archive

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

PATCH 1/1 x86/efi: use GFP_ATOMIC under spin_lock

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +1 -1
index 0c2a234fef1e..f5adcadb381b 100644
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

A message that is not in the archive (sent off-list or not yet received): [email protected]

#2 lore raw
Quoted 11 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +0 -0
index 0c2a234fef1e..f5adcadb381b 100644

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 96

Quoted 8 lines
arch/x86/platform/efi/efi_64.c +1 -1
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

The allocation there, if it happens within a spinlocked path, is probably a layering violation - and GFP_ATOMIC is at best a workaround.

Thanks,

Ingo

A message that is not in the archive (sent off-list or not yet received): [email protected]

#4 lore raw
Quoted 20 lines · Ingo Molnar
Quoted 17 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +1 -1
index 0c2a234fef1e..f5adcadb381b 100644
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
Quoted 7 lines

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 96

Quoted 2 lines
arch/x86/platform/efi/efi_64.c +0 -0
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

The allocation there, if it happens within a spinlocked path, is probably a layering violation - and GFP_ATOMIC is at best a workaround.

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

regards,
dan carpenter

#5 lore raw
Quoted 29 lines · Dan Carpenter
Quoted 20 lines · Ingo Molnar
Quoted 17 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +1 -1
index 0c2a234fef1e..f5adcadb381b 100644
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
Quoted 7 lines

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 96

Quoted 2 lines
arch/x86/platform/efi/efi_64.c +0 -0
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

The allocation there, if it happens within a spinlocked path, is probably a layering violation - and GFP_ATOMIC is at best a workaround.

Quoted 2 lines

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

It's a generic pattern: GFP_KERNEL -> GFP_ATOMIC fixes are almost always wrong.

Thanks,

Ingo

#6 lore raw
Quoted 32 lines · Ingo Molnar
Quoted 29 lines · Dan Carpenter
Quoted 27 lines · Ingo Molnar
Quoted 11 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +0 -0
index 0c2a234fef1e..f5adcadb381b 100644

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 96

Quoted 8 lines
arch/x86/platform/efi/efi_64.c +1 -1
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

The allocation there, if it happens within a spinlocked path, is probably a layering violation - and GFP_ATOMIC is at best a workaround.

Quoted 6 lines
Quoted 2 lines

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

It's a generic pattern: GFP_KERNEL -> GFP_ATOMIC fixes are almost always wrong.

I always feel that way too. :/ There are too many places where GFP_ATOMIC is used. I think it's great that you're going to fix this properly.

regards,
dan carpenter

#7 lore raw
In reply to Dan Carpenter
Quoted 3 lines · Dan Carpenter

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

Thanks for the patch Dan. Nice catch.

But I'm wondering if we can simply delete phys_efi_get_time() to avoid the whole problem of doing GFP_KERNEL allocations under a spinlock.

In fact, the whole EFI time stuff is looking a bit crusty.

I only see two direct users of efi.get_time() outside of arch,

drivers/char/efirtc.c
drivers/rtc/rtc-efi.c

which are both "depends on IA64". For x86, all other callers are inside arch/x86/platform/efi/efi.c,

efi_set_rtc_mmss()
efi_get_time()

neither of which have any callers - it all appears to be dead code. The diff stat of deleting all this dead code isn't too bad either,

 arch/x86/platform/efi/efi.c    | 151 ++---------------------------------------
 arch/x86/platform/efi/efi_64.c |  90 ------------------------
 2 files changed, 5 insertions(+), 236 deletions(-)

Thoughts?

---

From c17c2275d1969e99f4a6427293af1a533f2e5242 Mon Sep 17 00:00:00 2001
From: Matt Fleming <[email protected]>
Date: Sun, 9 Mar 2014 14:18:10 +0000
Subject: [PATCH] x86/efi: Remove EFI time functions

Dan reported that phys_efi_get_time() is doing kmalloc(..., GFP_KERNEL) under a spinlock which is very clearly a bug. However, the EFI time functions have been dead code for x86 since commit 04bf9ba720fc ("x86,
efi: Don't use (U)EFI time services on 32 bit").

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

Let's rip them out. If we find a need for them in the future, and if the runtime implementations of the time services improve considerably, the code can be put back.

Cc Dan Carpenter <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Nathan Zimmer <[email protected]>
Cc Matthew Garrett <[email protected]>
Cc Jan Beulich <[email protected]>
---
 arch/x86/platform/efi/efi.c    | 151 ++---------------------------------------
 arch/x86/platform/efi/efi_64.c |  90 ------------------------
 2 files changed, 5 insertions(+), 236 deletions(-)
arch/x86/platform/efi/efi.c +5 -146
index 43e7cf6c6111..fc1a8f639f7b 100644
@@ -40,14 +40,12 @@
 #include <linux/memblock.h>
 #include <linux/spinlock.h>
 #include <linux/uaccess.h>
-#include <linux/time.h>
 #include <linux/io.h>
 #include <linux/reboot.h>
 #include <linux/bcd.h>
 
 #include <asm/setup.h>
 #include <asm/efi.h>
-#include <asm/time.h>
 #include <asm/cacheflush.h>
 #include <asm/tlbflush.h>
 #include <asm/x86_init.h>
@@ -104,54 +102,6 @@ static int __init setup_storage_paranoia(char *arg)
 }
 early_param("efi_no_storage_paranoia", setup_storage_paranoia);
 
-static efi_status_t virt_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);
-	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)
-{
-	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)
-{
-	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)
-{
-	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,
 					  efi_guid_t *vendor,
 					  u32 *attr,
@@ -194,11 +144,6 @@ static efi_status_t virt_efi_query_variable_info(u32 attr,
 			      remaining_space, max_variable_size);
 }
 
-static efi_status_t virt_efi_get_next_high_mono_count(u32 *count)
-{
-	return efi_call_virt1(get_next_high_mono_count, count);
-}
-
 static void virt_efi_reset_system(int reset_type,
 				  efi_status_t status,
 				  unsigned long data_size,
@@ -246,72 +191,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
 	return status;
 }
 
-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, virt_to_phys(tm),
-				virt_to_phys(tc));
-	efi_call_phys_epilog();
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return status;
-}
-
-int efi_set_rtc_mmss(const struct timespec *now)
-{
-	unsigned long nowtime = now->tv_sec;
-	efi_status_t	status;
-	efi_time_t	eft;
-	efi_time_cap_t	cap;
-	struct rtc_time	tm;
-
-	status = efi.get_time(&eft, &cap);
-	if (status != EFI_SUCCESS) {
-		pr_err("Oops: efitime: can't read time!\n");
-		return -1;
-	}
-
-	rtc_time_to_tm(nowtime, &tm);
-	if (!rtc_valid_tm(&tm)) {
-		eft.year = tm.tm_year + 1900;
-		eft.month = tm.tm_mon + 1;
-		eft.day = tm.tm_mday;
-		eft.minute = tm.tm_min;
-		eft.second = tm.tm_sec;
-		eft.nanosecond = 0;
-	} else {
-		pr_err("%s: Invalid EFI RTC value: write of %lx to EFI RTC failed\n",
-		       __func__, nowtime);
-		return -1;
-	}
-
-	status = efi.set_time(&eft);
-	if (status != EFI_SUCCESS) {
-		pr_err("Oops: efitime: can't write time!\n");
-		return -1;
-	}
-	return 0;
-}
-
-void efi_get_time(struct timespec *now)
-{
-	efi_status_t status;
-	efi_time_t eft;
-	efi_time_cap_t cap;
-
-	status = efi.get_time(&eft, &cap);
-	if (status != EFI_SUCCESS)
-		pr_err("Oops: efitime: can't read time!\n");
-
-	now->tv_sec = mktime(eft.year, eft.month, eft.day, eft.hour,
-			     eft.minute, eft.second);
-	now->tv_nsec = 0;
-}
-
 /*
  * Tell the kernel about the EFI memory map.  This might include
  * more than the max 128 entries that can fit in the e820 legacy
@@ -588,20 +467,12 @@ static int __init efi_runtime_init32(void)
 	}
 
 	/*
-	 * We will only need *early* access to the following two
-	 * EFI runtime services before set_virtual_address_map
-	 * is invoked.
+	 * We will only need *early* access to the following EFI runtime
+	 * service before set_virtual_address_map is invoked.
 	 */
-	efi_phys.get_time = (efi_get_time_t *)
-			(unsigned long)runtime->get_time;
 	efi_phys.set_virtual_address_map  			(efi_set_virtual_address_map_t *)
 			(unsigned long)runtime->set_virtual_address_map;
-	/*
-	 * Make efi_get_time can be called before entering
-	 * virtual mode.
-	 */
-	efi.get_time = phys_efi_get_time;
 	early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
 
 	return 0;
@@ -619,20 +490,13 @@ static int __init efi_runtime_init64(void)
 	}
 
 	/*
-	 * We will only need *early* access to the following two
-	 * EFI runtime services before set_virtual_address_map
-	 * is invoked.
+	 * We will only need *early* access to the following EFI runtime
+	 * service before set_virtual_address_map is invoked.
 	 */
-	efi_phys.get_time = (efi_get_time_t *)
-			(unsigned long)runtime->get_time;
 	efi_phys.set_virtual_address_map  			(efi_set_virtual_address_map_t *)
 			(unsigned long)runtime->set_virtual_address_map;
-	/*
-	 * Make efi_get_time can be called before entering
-	 * virtual mode.
-	 */
-	efi.get_time = phys_efi_get_time;
+
 	early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
 
 	return 0;
@@ -880,14 +744,9 @@ void __init old_map_region(efi_memory_desc_t *md)
 
 static void native_runtime_setup(void)
 {
-	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;
 	efi.get_variable = virt_efi_get_variable;
 	efi.get_next_variable = virt_efi_get_next_variable;
 	efi.set_variable = virt_efi_set_variable;
-	efi.get_next_high_mono_count = virt_efi_get_next_high_mono_count;
 	efi.reset_system = virt_efi_reset_system;
 	efi.query_variable_info = virt_efi_query_variable_info;
 	efi.update_capsule = virt_efi_update_capsule;
arch/x86/platform/efi/efi_64.c +0 -90

117 lines not on this page · raw message

Signature · 4 lines
1.8.5.3

-- 
Matt Fleming, Intel Open Source Technology Center
#8 lore raw
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Signature · 1 line
Matthew Garrett | [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#10 lore raw
Quoted 10 lines · Matthew Garrett
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

I can check again, but I'm pretty sure this ASUS machine under my desk always returns a vendor-specific error code when invoked, even with Borislav's 1:1 patches. Enabling EFI services just because they exist hasn't worked out well for us in the past.

So enabling them is fine, but we certainly need some kind of priority mechanism so they're used as a last resort and some ironclad use case of why we absolutely must have this.

And of course, the GPF_KERNEL alloc under spinlock bug that started this thread needs to be fixed.

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#11 lore raw
Quoted 3 lines · Matt Fleming

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

In theory we get timezones, which we otherwise only get if we have an ACPI TAD device.

Quoted 4 lines

I can check again, but I'm pretty sure this ASUS machine under my desk always returns a vendor-specific error code when invoked, even with Borislav's 1:1 patches. Enabling EFI services just because they exist hasn't worked out well for us in the past.

Returning an error doesn't seem like a problem, as long as it's not actually killing the machine in the process...

Quoted 2 lines

And of course, the GPF_KERNEL alloc under spinlock bug that started this thread needs to be fixed.

Losing phys_efi_get_time() doesn't seem like it ought to be much of a problem.

Signature · 1 line
Matthew Garrett | [email protected]

A message that is not in the archive (sent off-list or not yet received): [email protected]

#13 lore raw
Quoted 8 lines · Matthew Garrett
Quoted 3 lines · Matt Fleming

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

In theory we get timezones, which we otherwise only get if we have an ACPI TAD device.

We'd previously discussed grabbing this in the EFI stub, before ExitBootServices(), assuming that we only want to get the timezone as opposed to setting it. We don't need phys_* and virt_* functions in the kernel proper for that.

Quoted 7 lines
Quoted 4 lines

I can check again, but I'm pretty sure this ASUS machine under my desk always returns a vendor-specific error code when invoked, even with Borislav's 1:1 patches. Enabling EFI services just because they exist hasn't worked out well for us in the past.

Returning an error doesn't seem like a problem, as long as it's not actually killing the machine in the process...

True, but I don't think that's a good enough justificaton for letting those functions live.

If someone can show me a platform where they're needed/advantageous, then that's a different story.

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center

A message that is not in the archive (sent off-list or not yet received): 20140309185028.GB10262-HNK1S37rvNbeXh+fF434Mdi2O/[email protected]

#15 lore raw
Quoted 10 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 8 lines · Matthew Garrett
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

Quoted 6 lines
Quoted 2 lines

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

Is it such a bad thing to be prepared for this sort of machine to arrive even if likely there are none so far?

Jan

#16 lore raw
Quoted 14 lines · Jan Beulich
Quoted 14 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 11 lines · Matthew Garrett
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Quoted 6 lines
Quoted 3 lines

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

Is it such a bad thing to be prepared for this sort of machine to arrive even if likely there are none so far?

"Be prepared for a not yet existing machine" != "time to give them another go on existing machines", right?

Thanks,

Ingo

#17 lore raw
Quoted 22 lines
Quoted 1 line
Quoted 1 line · Ingo Molnar
Quoted 18 lines · Jan Beulich
Quoted 17 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 11 lines · Matthew Garrett
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

Quoted 5 lines
Quoted 2 lines

Is it such a bad thing to be prepared for this sort of machine to arrive even if likely there are none so far?

"Be prepared for a not yet existing machine" != "time to give them another go on existing machines", right?

That heavily depends on the perspective you take, and I know we tend to have disagreeing perspectives here: I think things should be done the intended way on all systems where this is possible. Remember the far from insignificant number of issues with the ACPI interrupt source overrides for particularly the timer interrupt years ago? Which wasn't a reason to stop trying to use ACPI wherever possible, even on affected systems (by introducing command line overrides).

Jan

#18 lore raw
Quoted 22 lines · Jan Beulich
Quoted 22 lines
Quoted 1 line
Quoted 1 line · Ingo Molnar
Quoted 18 lines · Jan Beulich
Quoted 17 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 11 lines · Matthew Garrett
Quoted 5 lines · Matt Fleming

We have tried to use the time functions before, with little success because of various bugs in the runtime implementations, e.g. see commit bacef661acdb ("x86-64/efi: Use EFI to deal with platform wall clock") and commit bd52276fa1d4 ("x86-64/efi: Use EFI to deal with platform wall clock (again)").

I'd naively expected that these would be more reliable after the 1:1 mapping patches, so it might actually be time to give them another go.

Is there any value in that? Do machines exist where we absolutely must have access to the EFI time services? Either because there's no other method or no other working one?

Quoted 7 lines
Quoted 5 lines
Quoted 2 lines

Is it such a bad thing to be prepared for this sort of machine to arrive even if likely there are none so far?

"Be prepared for a not yet existing machine" != "time to give them another go on existing machines", right?

That heavily depends on the perspective you take, [...]

The inequality I mention above is purely factual, so it does not depend on perspective.

Quoted 3 lines

[...] and I know we tend to have disagreeing perspectives here: I think things should be done the intended way on all systems where this is possible. [...]

The problem is that on 99% of these systems the "intended way" at hardware design time was to run Windows and only Windows.

Firmware interfacing problems are a lot less severe on ARM, where 99% of the systems are intended to run Linux.

So it's all inflicted on us artificially, and when it comes to Windows hardware we have no choice but to act defensively, not in an optimistic, anticipatory fashion.

Quoted 5 lines

[...] Remember the far from insignificant number of issues with the ACPI interrupt source overrides for particularly the timer interrupt years ago? Which wasn't a reason to stop trying to use ACPI wherever possible, even on affected systems (by introducing command line overrides).

That's an apples to oranges comparison IMO, the motivation for that was real on real systems: to get high(er) resolution time and interrupt sources.

What's the upside here, for existing systems? Please don't mistake me:
if an upside exists I'm not against it, at all.

Thanks,

Ingo

#19 lore raw
Quoted 10 lines
Quoted 6 lines
Quoted 1 line · Ingo Molnar

[...] Remember the far from insignificant number of issues with the ACPI interrupt source overrides for particularly the timer interrupt years ago? Which wasn't a reason to stop trying to use ACPI wherever possible, even on affected systems (by introducing command line overrides).

That's an apples to oranges comparison IMO, the motivation for that was real on real systems: to get high(er) resolution time and interrupt sources.

What has that got to do with getting higher resolution? IRQ0 is IRQ0, irrespective whether driven by an 8254 or a HPET. The workaround was needed to get IRQ0 to work properly _at all_.

Quoted 2 lines

What's the upside here, for existing systems? Please don't mistake me:
if an upside exists I'm not against it, at all.

The upside isn't so much on existing systems that work with the intended model, but on those that don't: Increasing awareness and pressure on the firmware vendors' side to get their bugs fixed. Just like - afaict - the ratio of systems with broken ACPI tables has gone down over time.

Just to give an example from the Xen side: Xen uses the time interface in UEFI, as you would expect not without problems. Apart from issues with memory areas needed by those runtime calls not being properly marked for runtime use (which the respective vendors accepted they need to fix), we are also facing problems with runtime calls using XMM registers. Rather than blindly saying "the specification isn't precise on this, and e.g. Linux has a half baked mechanism to deal with this, so let's just do so too" we're pushing for the specification to get updated, such that it becomes clear whether the firmware may do so and we need to change Xen, or whether it's the firmware people needing to fix their implementation. Doing it that way is cumbersome, yes, but I think it is in the best interest of everybody involved (and better than papering over bugs by avoiding certain functionality). And yes, should such a machine reach customer hands, and should we get reports that there's no way for them to boot it with Xen, we can always add a command line override telling the hypervisor to avoid the broken runtime service and use direct CMOS accesses instead.

The approach you lobby - avoid the runtime service by default - will just result in further delaying the fixing of the firmware bugs.

(The one real upside - getting time zone information - was already mentioned by someone else on this thread.)

Jan

#20 lore raw
Quoted 6 lines · Jan Beulich

The upside isn't so much on existing systems that work with the intended model, but on those that don't: Increasing awareness and pressure on the firmware vendors' side to get their bugs fixed. Just like - afaict - the ratio of systems with broken ACPI tables has gone down over time.

I'm not saying that we can never use the time functions. All I'm saying is that until there are actaul in-kernel users let's delete the code. Feel free to bring them back when someone actually needs them.

We're evaluating the tradeoff between having the code around for future use, and the resultant maintenance burden whenever the EFI code gets refactored. Clearly the code is bitrotting, which is the issue that started this thread. No, it's not bitrotting very fast, and yes things still build, but code can't bitrot at all if it doesn't exist.

I think we're all pretty much agreed that at the very least phys_efi_get_time() can go in the bin. Whatever the outcome of this thread that'll happen. The question is whether it makes sense to rip out all of the time stuff in one go.

Quoted 6 lines

Just to give an example from the Xen side: Xen uses the time interface in UEFI, as you would expect not without problems. Apart from issues with memory areas needed by those runtime calls not being properly marked for runtime use (which the respective vendors accepted they need to fix), we are also facing problems with runtime calls using XMM registers.

Presumably you've got some kind of quirk mechanism to get things working? That doesn't exist in the kernel so the time functions as-is are useless, right? What's the benefit of using the EFI time services for Xen? Does Xen use the current kernel functions directly?

But this is good, here is a concrete use case.

Regarding the XMM updates...

Quoted 8 lines

Rather than blindly saying "the specification isn't precise on this, and e.g. Linux has a half baked mechanism to deal with this, so let's just do so too" we're pushing for the specification to get updated, such that it becomes clear whether the firmware may do so and we need to change Xen, or whether it's the firmware people needing to fix their implementation. Doing it that way is cumbersome, yes, but I think it is in the best interest of everybody involved (and better than papering over bugs by avoiding certain functionality).

Pushing for clarification in the spec is definitely a good idea, and I commend you for doing that. But you're talking about fundamental calling conventions here, you're not discussing peripheral services that have a track record of bearly being tested at runtime and of arguably limited value when things do work.

But we're getting off topic here.

Quoted 2 lines

(The one real upside - getting time zone information - was already mentioned by someone else on this thread.)

We can easily do that from the EFI boot stub, we don't need runtime services to do that. And even if we did need runtime services, someone needs to show me the patches that use them.

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center

A message that is not in the archive (sent off-list or not yet received): 20140310104328.GG10262-HNK1S37rvNbeXh+fF434Mdi2O/[email protected]

#22 lore raw
Quoted 11 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 6 lines · Jan Beulich

Just to give an example from the Xen side: Xen uses the time interface in UEFI, as you would expect not without problems. Apart from issues with memory areas needed by those runtime calls not being properly marked for runtime use (which the respective vendors accepted they need to fix), we are also facing problems with runtime calls using XMM registers.

Presumably you've got some kind of quirk mechanism to get things working?

Not yet, since so far we haven't been shown issues with the code on other than non-production systems.

Quoted 2 lines

That doesn't exist in the kernel so the time functions as-is are useless, right?

Not sure why you call them useless. If wired up properly, they would be useful on systems where they work.

Quoted 1 line

What's the benefit of using the EFI time services for Xen?

As said before: Don't suffer from there not being any wallclock if there's no CMOS clock. With there even being a FADT flag to indicate its absence, there clearly must be plans to have such machines.

Quoted 1 line

Does Xen use the current kernel functions directly?

Which kernel functions? Perhaps just a misunderstanding - I gave that example with the actual hypervisor in mind, not the kernel side code sitting on top. The kernel, after all, can't directly call EFI runtime code when running on top of Xen.

Jan

A message that is not in the archive (sent off-list or not yet received): 531DAA7602000078001224EF-ce6RLXgGx+vWGUEhTRrCg1aTQe2KTcn/@public.gmane.org

#24 lore raw
Quoted 3 lines · Jan Beulich

Not sure why you call them useless. If wired up properly, they would be useful on systems where they work.

They're useless in the sense that they have no users in the kernel currently.

Quoted 4 lines

Which kernel functions? Perhaps just a misunderstanding - I gave that example with the actual hypervisor in mind, not the kernel side code sitting on top. The kernel, after all, can't directly call EFI runtime code when running on top of Xen.

OK, that's my bad, I misunderstood what you were saying.

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#25 lore raw
In reply to Matt Fleming
Quoted 5 lines · Matt Fleming

I think we're all pretty much agreed that at the very least phys_efi_get_time() can go in the bin. Whatever the outcome of this thread that'll happen. The question is whether it makes sense to rip out all of the time stuff in one go.

OK, I'm chickening out of doing the full delete for v3.15. How about something like this instead?

---

From 697c512d44415794396773533715dff45785c585 Mon Sep 17 00:00:00 2001
From: Matt Fleming <[email protected]>
Date: Thu, 13 Mar 2014 19:41:08 +0000
Subject: [PATCH] x86/efi: Rip out phys_efi_get_time()

Dan reported that phys_efi_get_time() is doing kmalloc(..., GFP_KERNEL) under a spinlock which is very clearly a bug. Since phys_efi_get_time() has no users let's just delete it instead of trying to fix it.

Note that since there are no users of phys_efi_get_time(), it is not possible to actually trigger a GFP_KERNEL alloc under the spinlock.

Cc Ingo Molnar <[email protected]>
Cc H. Peter Anvin <[email protected]>
Cc Nathan Zimmer <[email protected]>
Cc Matthew Garrett <[email protected]>
Cc Jan Beulich <[email protected]>
---
 arch/x86/platform/efi/efi.c | 29 -----------------------------
 1 file changed, 29 deletions(-)
arch/x86/platform/efi/efi.c +0 -29
index 395decedfa2b..872214435e9d 100644
@@ -256,21 +256,6 @@ static efi_status_t __init phys_efi_set_virtual_address_map(
 	return status;
 }
 
-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, virt_to_phys(tm),
-				virt_to_phys(tc));
-	efi_call_phys_epilog();
-	spin_unlock_irqrestore(&rtc_lock, flags);
-	return status;
-}
-
 int efi_set_rtc_mmss(const struct timespec *now)
 {
 	unsigned long nowtime = now->tv_sec;
@@ -604,16 +589,9 @@ static int __init efi_runtime_init32(void)
 	 * EFI runtime services before set_virtual_address_map
 	 * is invoked.
 	 */
-	efi_phys.get_time = (efi_get_time_t *)
-			(unsigned long)runtime->get_time;
 	efi_phys.set_virtual_address_map  			(efi_set_virtual_address_map_t *)
 			(unsigned long)runtime->set_virtual_address_map;
-	/*
-	 * Make efi_get_time can be called before entering
-	 * virtual mode.
-	 */
-	efi.get_time = phys_efi_get_time;
 	early_iounmap(runtime, sizeof(efi_runtime_services_32_t));
 
 	return 0;
@@ -635,16 +613,9 @@ static int __init efi_runtime_init64(void)
 	 * EFI runtime services before set_virtual_address_map
 	 * is invoked.
 	 */
-	efi_phys.get_time = (efi_get_time_t *)
-			(unsigned long)runtime->get_time;
 	efi_phys.set_virtual_address_map  			(efi_set_virtual_address_map_t *)
 			(unsigned long)runtime->set_virtual_address_map;
-	/*
-	 * Make efi_get_time can be called before entering
-	 * virtual mode.
-	 */
-	efi.get_time = phys_efi_get_time;
 	early_iounmap(runtime, sizeof(efi_runtime_services_64_t));
 
 	return 0;
Signature · 4 lines
1.8.5.3

-- 
Matt Fleming, Intel Open Source Technology Center
#26 lore raw
In reply to Jan Beulich
Quoted 3 lines · Jan Beulich

Is it such a bad thing to be prepared for this sort of machine to arrive even if likely there are none so far?

I think it's a bad thing for us to carry code in the kernel that has no users, yes.

If someone wants it in the future, they can pull it out of git.

Signature · 1 line
Matt Fleming, Intel Open Source Technology Center
#27 lore raw
In reply to Matt Fleming
Quoted 11 lines
Quoted 1 line
Quoted 1 line · Matt Fleming
Quoted 3 lines · Dan Carpenter

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

Thanks for the patch Dan. Nice catch.

But I'm wondering if we can simply delete phys_efi_get_time() to avoid the whole problem of doing GFP_KERNEL allocations under a spinlock.

Quoted 8 lines

In fact, the whole EFI time stuff is looking a bit crusty.

I only see two direct users of efi.get_time() outside of arch,

drivers/char/efirtc.c
drivers/rtc/rtc-efi.c

which are both "depends on IA64".

And wrongly so. I continue to think that the fact that various firmware implementations are broken should not make us by default avoid using proper abstraction functionality whenever possible. There's a reason behind that abstraction after all...

Quoted 6 lines

For x86, all other callers are inside
arch/x86/platform/efi/efi.c,

efi_set_rtc_mmss()
efi_get_time()

Quoted 8 lines

neither of which have any callers - it all appears to be dead code. The diff stat of deleting all this dead code isn't too bad either,

 arch/x86/platform/efi/efi.c    | 151 ++---------------------------------------
 arch/x86/platform/efi/efi_64.c |  90 ------------------------
 2 files changed, 5 insertions(+), 236 deletions(-)

Thoughts?

Please don't, except perhaps for the phys_efi_get_time() removal.

Jan

#28 lore raw
In reply to Matt Fleming
Quoted 23 lines · Matt Fleming
Quoted 3 lines · Dan Carpenter

You're on your own for fixing the complicated stuff like layering violations. I just do static checker stuff and sed fixes. ;)

Thanks for the patch Dan. Nice catch.

But I'm wondering if we can simply delete phys_efi_get_time() to avoid the whole problem of doing GFP_KERNEL allocations under a spinlock.

In fact, the whole EFI time stuff is looking a bit crusty.

I only see two direct users of efi.get_time() outside of arch,

drivers/char/efirtc.c
drivers/rtc/rtc-efi.c

which are both "depends on IA64". For x86, all other callers are inside arch/x86/platform/efi/efi.c,

efi_set_rtc_mmss()
efi_get_time()

Quoted 8 lines

neither of which have any callers - it all appears to be dead code. The diff stat of deleting all this dead code isn't too bad either,

 arch/x86/platform/efi/efi.c    | 151 ++---------------------------------------
 arch/x86/platform/efi/efi_64.c |  90 ------------------------
 2 files changed, 5 insertions(+), 236 deletions(-)

Thoughts?

I don't have strong opinions on this, this was just a static checker thing, and I don't know the code.

regards,
dan carpenter

#29 lore raw
In reply to a message not in the archive
Quoted 11 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +0 -0
index 0c2a234fef1e..f5adcadb381b 100644

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 93

Quoted 5 lines
arch/x86/platform/efi/efi_64.c +1 -1
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);

"save_pgd" is a file scope variable. It wouldn't be that hard to move the allocation to a different function. Meanwhile I am on the way to the airport for vacation.

See you guys in couple weeks.

regards,
dan carpenter

#30 lore raw
In reply to Dan Carpenter
Quoted 12 lines · Dan Carpenter

In phys_efi_get_time() we call efi_call_phys_prelog() with a spin_lock so this allocation should be atomic.

Fixes b8f2c21db390 ('efi, x86: Pass a proper identity mapping in efi_call_phys_prelog')
arch/x86/platform/efi/efi_64.c +0 -0
index 0c2a234fef1e..f5adcadb381b 100644

arch/x86/platform/efi/efi_64.c void __init efi_call_phys_prelog(void) · line 96

Quoted 8 lines
arch/x86/platform/efi/efi_64.c +1 -1
@@ -90,7 +90,7 @@ void __init efi_call_phys_prelog(void)
 	local_irq_save(efi_flags);
 
 	n_pgds = DIV_ROUND_UP((max_pfn << PAGE_SHIFT), PGDIR_SIZE);
-	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_KERNEL);
+	save_pgd = kmalloc(n_pgds * sizeof(pgd_t), GFP_ATOMIC);
 
 	for (pgd = 0; pgd < n_pgds; pgd++) {
 		save_pgd[pgd] = *pgd_offset_k(pgd * PGDIR_SIZE);

And what happens if the allocation fails, as GFP_ATOMIC allocations are wont to do? I see an inbound NULL pointer reference from miles away here...

-hpa