Skip to contentSkip to conversation

EFI support backports

PATCH Applied Darren Hart 2 participants 5 messages Dec 7, 2011

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

cover EFI support backports

From: Darren Hart <[email protected]>

The following patches have been merged back from upstream to address various issues with the EFI boot process. These are intended to be merged with yocto/standard/base.

Please watch for a subsequent patch adding a series of efi config fragments.

The following changes since commit ab1de8c21d2b1d084b8488496d75cc54fcd94f02:

Merge commit 'v3.0.10' into yocto/standard/base (2011-11-23 00:31:29 -0500)

are available in the git repository at:

git://git.infradead.org/users/dvhart/linux-yocto-3.0.git dvhart/standard/efi
http://git.infradead.org/users/dvhart/linux-yocto-3.0.git/shortlog/refs/heads/dvhart/standard/efi

Matt Fleming (2):
x86/rtc: Don't recursively acquire rtc_lock
x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware

Maurice Ma (1):
x86, efi: Convert efi_phys_get_time() args to physical addresses

 arch/x86/kernel/rtc.c          |   23 ++++++++++++-----------
 arch/x86/platform/efi/efi.c    |    3 ++-
 arch/x86/platform/efi/efi_32.c |   22 +++++++++++++---------
 arch/x86/platform/mrst/vrtc.c  |    9 +++++++++
 4 files changed, 36 insertions(+), 21 deletions(-)
Signature · 1 line
1.7.6.4
#1 lore raw

PATCH 1/3 x86/rtc: Don't recursively acquire rtc_lock

From: Matt Fleming <[email protected]>

A deadlock was introduced on x86 in commit ef68c8f87ed1 ("x86:
Serialize EFI time accesses on rtc_lock") because efi_get_time() and friends can be called with rtc_lock already held by read_persistent_time(), e.g.:

timekeeping_init()
read_persistent_clock() <-- acquire rtc_lock
efi_get_time()
phys_efi_get_time() <-- acquire rtc_lock <DEADLOCK>

To fix this let's push the locking down into the get_wallclock() and set_wallclock() implementations. Only the clock implementations that access the x86 RTC directly need to acquire rtc_lock, so it makes sense to push the locking down into the rtc, vrtc and efi code.

The virtualization implementations don't require rtc_lock to be held because they provide their own serialization.

---
 arch/x86/kernel/rtc.c         |   23 ++++++++++++-----------
 arch/x86/platform/mrst/vrtc.c |    9 +++++++++
 2 files changed, 21 insertions(+), 11 deletions(-)
arch/x86/kernel/rtc.c +12 -11
index 3f2ad26..ccdbc16 100644
@@ -42,8 +42,11 @@ int mach_set_rtc_mmss(unsigned long nowtime)
 {
 	int real_seconds, real_minutes, cmos_minutes;
 	unsigned char save_control, save_freq_select;
+	unsigned long flags;
 	int retval = 0;
 
+	spin_lock_irqsave(&rtc_lock, flags);
+
 	 /* tell the clock it's being set */
 	save_control = CMOS_READ(RTC_CONTROL);
 	CMOS_WRITE((save_control|RTC_SET), RTC_CONTROL);
@@ -93,12 +96,17 @@ int mach_set_rtc_mmss(unsigned long nowtime)
 	CMOS_WRITE(save_control, RTC_CONTROL);
 	CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
 
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	return retval;
 }
 
 unsigned long mach_get_cmos_time(void)
 {
 	unsigned int status, year, mon, day, hour, min, sec, century = 0;
+	unsigned long flags;
+
+	spin_lock_irqsave(&rtc_lock, flags);
 
 	/*
 	 * If UIP is clear, then we have >= 244 microseconds before
@@ -125,6 +133,8 @@ unsigned long mach_get_cmos_time(void)
 	status = CMOS_READ(RTC_CONTROL);
 	WARN_ON_ONCE(RTC_ALWAYS_BCD && (status & RTC_DM_BINARY));
 
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	if (RTC_ALWAYS_BCD || !(status & RTC_DM_BINARY)) {
 		sec = bcd2bin(sec);
 		min = bcd2bin(min);
@@ -169,24 +179,15 @@ EXPORT_SYMBOL(rtc_cmos_write);
 
 int update_persistent_clock(struct timespec now)
 {
-	unsigned long flags;
-	int retval;
-
-	spin_lock_irqsave(&rtc_lock, flags);
-	retval = x86_platform.set_wallclock(now.tv_sec);
-	spin_unlock_irqrestore(&rtc_lock, flags);
-
-	return retval;
+	return x86_platform.set_wallclock(now.tv_sec);
 }
 
 /* not static: needed by APM */
 void read_persistent_clock(struct timespec *ts)
 {
-	unsigned long retval, flags;
+	unsigned long retval;
 
-	spin_lock_irqsave(&rtc_lock, flags);
 	retval = x86_platform.get_wallclock();
-	spin_unlock_irqrestore(&rtc_lock, flags);
 
 	ts->tv_sec = retval;
 	ts->tv_nsec = 0;
arch/x86/platform/mrst/vrtc.c +9 -0
index 73d70d6..6d5dbcd 100644
@@ -58,8 +58,11 @@ EXPORT_SYMBOL_GPL(vrtc_cmos_write);
 unsigned long vrtc_get_time(void)
 {
 	u8 sec, min, hour, mday, mon;
+	unsigned long flags;
 	u32 year;
 
+	spin_lock_irqsave(&rtc_lock, flags);
+
 	while ((vrtc_cmos_read(RTC_FREQ_SELECT) & RTC_UIP))
 		cpu_relax();
 
@@ -70,6 +73,8 @@ unsigned long vrtc_get_time(void)
 	mon = vrtc_cmos_read(RTC_MONTH);
 	year = vrtc_cmos_read(RTC_YEAR);
 
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	/* vRTC YEAR reg contains the offset to 1960 */
 	year += 1960;
 
@@ -83,8 +88,10 @@ unsigned long vrtc_get_time(void)
 int vrtc_set_mmss(unsigned long nowtime)
 {
 	int real_sec, real_min;
+	unsigned long flags;
 	int vrtc_min;
 
+	spin_lock_irqsave(&rtc_lock, flags);
 	vrtc_min = vrtc_cmos_read(RTC_MINUTES);
 
 	real_sec = nowtime % 60;
@@ -95,6 +102,8 @@ int vrtc_set_mmss(unsigned long nowtime)
 
 	vrtc_cmos_write(real_sec, RTC_SECONDS);
 	vrtc_cmos_write(real_min, RTC_MINUTES);
+	spin_unlock_irqrestore(&rtc_lock, flags);
+
 	return 0;
 }
 
Signature · 1 line
1.7.6.4
#2 lore raw

PATCH 2/3 x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware

In reply to Darren Hart

From: Matt Fleming <[email protected]>

efi_call_phys_prelog() assumes that the kernel was loaded at a physical address within the first 8MB of ram, usually 0x1000000. However, this isn't the case with a CONFIG_RELOCATABLE=y kernel which could have been loaded anywhere in the physical address space.

Replace the hardcoded pgd_index(0) and pgd_index(PAGE_OFFSET) with the runtime addresses of the kernel in the physical and virtual space, respectively.

Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Matthew Garrett <[email protected]>
---
 arch/x86/platform/efi/efi_32.c |   22 +++++++++++++---------
 1 files changed, 13 insertions(+), 9 deletions(-)
arch/x86/platform/efi/efi_32.c +13 -9
index 5cab48e..1156e9a 100644
@@ -44,8 +44,12 @@ void efi_call_phys_prelog(void)
 {
 	unsigned long cr4;
 	unsigned long temp;
+	unsigned long phys_addr, virt_addr;
 	struct desc_ptr gdt_descr;
 
+	virt_addr = (unsigned long)_text;
+	phys_addr = virt_addr - PAGE_OFFSET;
+
 	local_irq_save(efi_rt_eflags);
 
 	/*
@@ -57,18 +61,18 @@ void efi_call_phys_prelog(void)
 
 	if (cr4 & X86_CR4_PAE) {
 		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
-		swapper_pg_dir[0].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
+		    swapper_pg_dir[pgd_index(phys_addr)].pgd;
+		swapper_pg_dir[pgd_index(phys_addr)].pgd =
+		    swapper_pg_dir[pgd_index(virt_addr)].pgd;
 	} else {
 		efi_bak_pg_dir_pointer[0].pgd =
-		    swapper_pg_dir[pgd_index(0)].pgd;
+		    swapper_pg_dir[pgd_index(phys_addr)].pgd;
 		efi_bak_pg_dir_pointer[1].pgd =
-		    swapper_pg_dir[pgd_index(0x400000)].pgd;
-		swapper_pg_dir[pgd_index(0)].pgd =
-		    swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd;
-		temp = PAGE_OFFSET + 0x400000;
-		swapper_pg_dir[pgd_index(0x400000)].pgd =
+		    swapper_pg_dir[pgd_index(phys_addr + 0x400000)].pgd;
+		swapper_pg_dir[pgd_index(phys_addr)].pgd =
+		    swapper_pg_dir[pgd_index(virt_addr)].pgd;
+		temp = virt_addr + 0x400000;
+		swapper_pg_dir[pgd_index(phys_addr + 0x400000)].pgd =
 		    swapper_pg_dir[pgd_index(temp)].pgd;
 	}
 
Signature · 1 line
1.7.6.4
#3 lore raw

PATCH 3/3 x86, efi: Convert efi_phys_get_time() args to physical addresses

In reply to Darren Hart

From: Maurice Ma <[email protected]>

Because callers of efi_phys_get_time() pass virtual stack addresses as arguments, we need to find their corresponding physical addresses and when calling GetTime() in physical mode.

Without this patch the following line is printed on boot,

"Oops: efitime: can't read time!"

Cc Matthew Garrett <[email protected]>
Cc Thomas Gleixner <[email protected]>
Cc Ingo Molnar <[email protected]>
Cc "H. Peter Anvin" <[email protected]>
Cc Zhang Rui <[email protected]>
---
 arch/x86/platform/efi/efi.c |    3 ++-
 1 files changed, 2 insertions(+), 1 deletions(-)
arch/x86/platform/efi/efi.c +2 -1
index 899e393..4fd8217 100644
@@ -167,7 +167,8 @@ static efi_status_t __init phys_efi_get_time(efi_time_t *tm,
 	efi_status_t status;
 
 	efi_call_phys_prelog();
-	status = efi_call_phys2(efi_phys.get_time, tm, tc);
+	status = efi_call_phys2(efi_phys.get_time, virt_to_phys(tm),
+				virt_to_phys(tc));
 	efi_call_phys_epilog();
 	return status;
 }
Signature · 1 line
1.7.6.4
#4 lore raw
In reply to Darren Hart
Quoted 7 lines · Darren Hart

From: Darren Hart<[email protected]>

The following patches have been merged back from upstream to address various issues with the EFI boot process. These are intended to be merged with yocto/standard/base.

Please watch for a subsequent patch adding a series of efi config fragments.

Merged to base and all the BSP branches. I've put it in with my pending 3.0.12 pull request, which should be out ASAP.

Bruce

Quoted 23 lines

The following changes since commit ab1de8c21d2b1d084b8488496d75cc54fcd94f02:

   Merge commit 'v3.0.10' into yocto/standard/base (2011-11-23 00:31:29 -0500)

are available in the git repository at:

git://git.infradead.org/users/dvhart/linux-yocto-3.0.git dvhart/standard/efi
http://git.infradead.org/users/dvhart/linux-yocto-3.0.git/shortlog/refs/heads/dvhart/standard/efi

Matt Fleming (2):
x86/rtc: Don't recursively acquire rtc_lock
x86, efi: Make efi_call_phys_prelog() CONFIG_RELOCATABLE-aware

Maurice Ma (1):
x86, efi: Convert efi_phys_get_time() args to physical addresses

  arch/x86/kernel/rtc.c          |   23 ++++++++++++-----------
  arch/x86/platform/efi/efi.c    |    3 ++-
  arch/x86/platform/efi/efi_32.c |   22 +++++++++++++---------
  arch/x86/platform/mrst/vrtc.c  |    9 +++++++++
  4 files changed, 36 insertions(+), 21 deletions(-)