Re: [PATCH 1/2] [IA64] physical mode SAL calls

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



On Wed, Feb 07, 2007 at 03:19:06PM +0900, Horms wrote:
> Hi,
> 
> I am resending this patch, which is a consolidated version of 3 or 4
> patches sent late last year. It includes a few minor fixes, and
> I have removed the portion which caused the pal code not to be mapped.
> 
> I have been using this code successfully for a number of months on
> my Tiger box.

This is an update on the version I sent yesterday. I miss-diffed, sorry.

  * Remove arch/ia64/kernel/machine_kexec.c chunk as this
      is part of a separate change that alters the
      arguments that are passed to kexec's relocate_kernel()
  * Add missing arch/ia64/kernel/sal.c chunk

-- 
Simon Horman (Horms)
  horms@xxxxxxxxxxxx
  http://verge.net.au/~horms/

[IA64] physical mode SAL calls

Currently the EFI code will fall back to making real mode calls if the call
to map the EFI code fails. Unfortunately this only takes into account EFI
calls, but if EFI calls are made in physical mode SAL calls also need to be
made in physical mode. On a Tiger2 at least, forcing EFI to stay in
physical mode caues the boot to oops in a SAL call.

This patch changes things around by adding code to allow SAL calls to be
made in physical mode. I then makes this the path that is allways followed
- that is SAL calls are always physical with this patch.

This patch fixes things up so that physical SAL calls are made when
physical EFI calls are in operation, and virtual SAL calls when virtual EFI
calls are in poration. 

Curiously on my Tiger2, it seems that having SAL always physical, regadless
of if EFI is physical or virtual, actually works.

Signed-Off-By: Simon Horman <horms@xxxxxxxxxxxx>


 arch/ia64/kernel/Makefile   |    2 
 arch/ia64/kernel/efi.c      |    1 
 arch/ia64/kernel/sal.c      |   24 +++++++++++
 arch/ia64/kernel/sal_stub.S |   92 +++++++++++++++++++++++++++++++++++++++++++
 include/asm-ia64/sal.h      |   56 +++++++++++++++++---------
 include/linux/efi.h         |    1 
 6 files changed, 157 insertions(+), 19 deletions(-)

Index: linux-2.6/include/asm-ia64/sal.h
===================================================================
--- linux-2.6.orig/include/asm-ia64/sal.h	2007-02-07 13:25:17.000000000 +0900
+++ linux-2.6/include/asm-ia64/sal.h	2007-02-07 13:26:26.000000000 +0900
@@ -45,9 +45,45 @@
 
 extern spinlock_t sal_lock;
 
+struct ia64_sal_retval {
+	/*
+	 * A zero status value indicates call completed without error.
+	 * A negative status value indicates reason of call failure.
+	 * A positive status value indicates success but an
+	 * informational value should be printed (e.g., "reboot for
+	 * change to take effect").
+	 */
+	s64 status;
+	u64 v0;
+	u64 v1;
+	u64 v2;
+};
+
+typedef struct ia64_sal_retval (*ia64_sal_handler) (u64, ...);
+
 /* SAL spec _requires_ eight args for each call. */
-#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)	\
-	result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7)
+struct ia64_sal_retval sal_call_phys(ia64_sal_handler ia64_sal,
+				     unsigned long a0, unsigned long a1,
+				     unsigned long a2, unsigned long a3,
+				     unsigned long a4, unsigned long a5,
+				     unsigned long a6, unsigned long a7);
+struct ia64_sal_retval __sal_call_phys(ia64_sal_handler ia64_sal,
+				       unsigned long a0, unsigned long a1,
+				       unsigned long a2, unsigned long a3,
+				       unsigned long a4, unsigned long a5,
+				       unsigned long a6, unsigned long a7);
+
+#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)			\
+	result = efi.mapped ? 						\
+		 (*ia64_sal)((unsigned long)a0, (unsigned long)a1,	\
+		 	     (unsigned long)a2, (unsigned long)a3,	\
+		     	     (unsigned long)a4, (unsigned long)a5,	\
+		     	     (unsigned long)a6, (unsigned long)a7) :	\
+		 sal_call_phys(ia64_sal,				\
+		             (unsigned long)a0, (unsigned long)a1,	\
+			     (unsigned long)a2, (unsigned long)a3,	\
+			     (unsigned long)a4, (unsigned long)a5,	\
+			     (unsigned long)a6, (unsigned long)a7);
 
 # define SAL_CALL(result,args...) do {				\
 	unsigned long __ia64_sc_flags;				\
@@ -95,22 +131,6 @@
 
 #define SAL_UPDATE_PAL			0x01000020
 
-struct ia64_sal_retval {
-	/*
-	 * A zero status value indicates call completed without error.
-	 * A negative status value indicates reason of call failure.
-	 * A positive status value indicates success but an
-	 * informational value should be printed (e.g., "reboot for
-	 * change to take effect").
-	 */
-	s64 status;
-	u64 v0;
-	u64 v1;
-	u64 v2;
-};
-
-typedef struct ia64_sal_retval (*ia64_sal_handler) (u64, ...);
-
 enum {
 	SAL_FREQ_BASE_PLATFORM = 0,
 	SAL_FREQ_BASE_INTERVAL_TIMER = 1,
Index: linux-2.6/arch/ia64/kernel/sal_stub.S
===================================================================
--- /dev/null	1970-01-01 00:00:00.000000000 +0000
+++ linux-2.6/arch/ia64/kernel/sal_stub.S	2007-02-07 13:26:26.000000000 +0900
@@ -0,0 +1,92 @@
+/*
+ * SAL call stub.
+ *
+ * Copyright (C) 2006 Horms <horms@xxxxxxxxxxxx>
+ *
+ * Based heavily on arch/ia64/kernel/efi_stub.S
+ *
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ *	David Mosberger <davidm@xxxxxxxxxx>
+ *
+ * This stub allows us to make PAL calls in physical mode with interrupts
+ * turned off. This is needed to make PAL calls if EFI has not been
+ * maped using SetVirtualMap() for one reason or another
+ */
+
+/*
+ * PSR settings as per SAL spec (Chapter 8 in the "IA-64 System
+ * Abstraction Layer Specification", revision 2.6e).  Note that
+ * psr.dfl and psr.dfh MUST be cleared, despite what this manual says.
+ * Otherwise, SAL dies whenever it's trying to do an IA-32 BIOS call
+ * (the br.ia instruction fails unless psr.dfl and psr.dfh are
+ * cleared).  Fortunately, SAL promises not to touch the floating
+ * point regs, so at least we don't have to save f2-f127.
+ */
+#define PSR_BITS_TO_CLEAR						\
+	(IA64_PSR_I | IA64_PSR_IT | IA64_PSR_DT | IA64_PSR_RT |		\
+	 IA64_PSR_DD | IA64_PSR_SS | IA64_PSR_RI | IA64_PSR_ED |	\
+	 IA64_PSR_DFL | IA64_PSR_DFH)
+
+#define PSR_BITS_TO_SET							\
+	(IA64_PSR_BN)
+
+#include <asm/processor.h>
+#include <asm/asmmacro.h>
+
+/*
+ * Inputs:
+ *	in0 = address of function descriptor of EFI routine to call
+ *	in1..in8 = arguments to routine
+ *
+ * Outputs:
+ *	r8..r11 = return
+ */
+
+GLOBAL_ENTRY(__sal_call_phys)
+	.prologue ASM_UNW_PRLG_RP|ASM_UNW_PRLG_PFS, ASM_UNW_PRLG_GRSAVE(9)
+	alloc loc1=ar.pfs,9,8,8,0
+	ld8 r2=[in0],8			// load SAL function's entry point
+	mov loc0=rp			// save return pointer
+	.body
+	;;
+	mov loc2=gp			// save global pointer
+	mov loc4=ar.rsc			// save RSE configuration
+	mov ar.rsc=0			// put RSE in enforced lazy, LE mode
+	;;
+	dep r2=0,r2,61,3		// __pa
+	ld8 gp=[in0]			// load EFI function's global pointer
+	movl r16=PSR_BITS_TO_CLEAR
+	mov loc3=psr
+	movl r17=PSR_BITS_TO_SET
+	;;
+	or loc3=loc3,r17
+	mov b6=r2
+	;;
+	dep gp=0,gp,61,3		// __pa
+	andcm r16=loc3,r16
+	br.call.sptk.many rp=ia64_switch_mode_phys
+.ret0:	mov out0=in1
+	mov out1=in2
+	mov out2=in3
+	mov out3=in4
+	mov out4=in5
+	mov out5=in6
+	mov out6=in7
+	mov out7=in8
+	mov loc5=r19
+	mov loc6=r20
+	;;
+	br.call.sptk.many rp=b6		// call the SAL function
+	;;
+	mov ar.rsc=0                    // put RSE in enforced lazy, LE mode
+	mov r16=loc3
+	mov r19=loc5
+	mov r20=loc6
+.ret1:	br.call.sptk.many rp=ia64_switch_mode_virt // return to virtual 	;;
+.ret2:	mov ar.rsc=loc4                 // restore RSE configuration
+	mov ar.pfs = loc1		// restore register stack
+	mov rp=loc0			// retore return pointer
+	mov gp=loc2			// retore global pointer
+	br.ret.sptk.many rp
+END(__sal_call_phys)
+
Index: linux-2.6/arch/ia64/kernel/Makefile
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/Makefile	2007-02-07 13:25:17.000000000 +0900
+++ linux-2.6/arch/ia64/kernel/Makefile	2007-02-07 13:26:26.000000000 +0900
@@ -7,7 +7,7 @@
 obj-y := acpi.o entry.o efi.o efi_stub.o gate-data.o fsys.o ia64_ksyms.o irq.o irq_ia64.o	\
 	 irq_lsapic.o ivt.o machvec.o pal.o patch.o process.o perfmon.o ptrace.o sal.o		\
 	 salinfo.o semaphore.o setup.o signal.o sys_ia64.o time.o traps.o unaligned.o \
-	 unwind.o mca.o mca_asm.o topology.o
+	 unwind.o mca.o mca_asm.o topology.o sal_stub.o
 
 obj-$(CONFIG_IA64_BRL_EMU)	+= brl_emu.o
 obj-$(CONFIG_IA64_GENERIC)	+= acpi-ext.o
Index: linux-2.6/include/linux/efi.h
===================================================================
--- linux-2.6.orig/include/linux/efi.h	2007-02-07 13:25:16.000000000 +0900
+++ linux-2.6/include/linux/efi.h	2007-02-07 13:26:26.000000000 +0900
@@ -265,6 +265,7 @@
 	efi_get_next_high_mono_count_t *get_next_high_mono_count;
 	efi_reset_system_t *reset_system;
 	efi_set_virtual_address_map_t *set_virtual_address_map;
+	unsigned mapped;
 } efi;
 
 static inline int
Index: linux-2.6/arch/ia64/kernel/efi.c
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/efi.c	2007-02-07 13:25:16.000000000 +0900
+++ linux-2.6/arch/ia64/kernel/efi.c	2007-02-07 13:27:54.000000000 +0900
@@ -601,6 +601,7 @@
 	efi.set_variable = virt_set_variable;
 	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
 	efi.reset_system = virt_reset_system;
+	efi.mapped = 1;
 }
 
 /*
Index: linux-2.6/arch/ia64/kernel/sal.c
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/sal.c	2007-02-07 13:25:16.000000000 +0900
+++ linux-2.6/arch/ia64/kernel/sal.c	2007-02-07 13:27:54.000000000 +0900
@@ -373,3 +373,27 @@ ia64_sal_oemcall_reentrant(struct ia64_sal_retval *isrvp, u64 oemfunc,
 	return 0;
 }
 EXPORT_SYMBOL(ia64_sal_oemcall_reentrant);
+
+/* In practice this seems to be needed for at least SAL_GET_STATE_INFO
+ * in Xen. Tested on a Tiger 2 box */
+struct ia64_sal_retval sal_call_phys(ia64_sal_handler ia64_sal,
+				    unsigned long a0, unsigned long a1,
+				    unsigned long a2, unsigned long a3,
+				    unsigned long a4, unsigned long a5,
+				    unsigned long a6, unsigned long a7)
+{
+       switch (a0) {
+       case SAL_GET_STATE_INFO:
+	       a3 = __pa(a3);
+	       break;
+       case SAL_MC_SET_PARAMS:
+	       if (a2 == 0x2) /* It is a memory address */
+		       a3 = __pa(a3);
+	       break;
+       case SAL_UPDATE_PAL:
+	       a1 = __pa(a1);
+	       a2 = __pa(a2);
+	       break;
+       }
+       return __sal_call_phys(ia64_sal, a0, a1, a2, a3, a4, a5, a6, a7);
+}
-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel]     [Sparc Linux]     [DCCP]     [Linux ARM]     [Yosemite News]     [Linux SCSI]     [Linux x86_64]     [Linux for Ham Radio]

  Powered by Linux