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

From: Horms <horms_at_verge.net.au>
Date: 2007-02-07 17:19:06
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.

-- 
Simon Horman (Horms)
  horms@verge.net.au
  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@verge.net.au>

 arch/ia64/kernel/Makefile        |    2 
 arch/ia64/kernel/efi.c           |    1 
 arch/ia64/kernel/machine_kexec.c |    3 -
 arch/ia64/kernel/sal_stub.S      |   92 ++++++++++++++++++++++++++++++++++++++
 include/asm-ia64/sal.h           |   56 +++++++++++++++--------
 include/linux/efi.h              |    1 
 6 files changed, 135 insertions(+), 20 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@verge.net.au>
+ *
+ * Based heavily on arch/ia64/kernel/efi_stub.S
+ *
+ * Copyright (C) 1999-2001 Hewlett-Packard Co
+ *	David Mosberger <davidm@hpl.hp.com>
+ *
+ * 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/machine_kexec.c
===================================================================
--- linux-2.6.orig/arch/ia64/kernel/machine_kexec.c	2007-02-07 13:25:16.000000000 +0900
+++ linux-2.6/arch/ia64/kernel/machine_kexec.c	2007-02-07 13:26:26.000000000 +0900
@@ -79,7 +79,8 @@
 	efi_system_table_t *systab;
 
 	systab = (efi_system_table_t *)__va(ia64_boot_param->efi_systab);
-	systab->runtime->set_virtual_address_map =
+	if (efi.mapped)
+		systab->runtime->set_virtual_address_map =
 				__pa(systab->runtime->set_virtual_address_map);
 	systab->runtime = (efi_runtime_services_t *)__pa(systab->runtime);
 
-
To unsubscribe from this list: send the line "unsubscribe linux-ia64" in
the body of a message to majordomo@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Received on Wed Feb 07 17:54:33 2007

This archive was generated by hypermail 2.1.8 : 2007-02-07 17:56:47 EST