--- x/xen/arch/ia64/linux-xen/Makefile
+++ x/xen/arch/ia64/linux-xen/Makefile
@@ -7,6 +7,7 @@ obj-y += mm_contig.o
 obj-y += pal.o
 obj-y += process-linux-xen.o
 obj-y += sal.o
+obj-y += sal_stub.o
 obj-y += setup.o
 obj-y += smpboot.o
 obj-y += smp.o
--- x/xen/arch/ia64/linux-xen/efi.c
+++ x/xen/arch/ia64/linux-xen/efi.c
@@ -418,6 +418,9 @@ efi_init (void)
 	u64 efi_desc_size;
 	char *cp, *end, vendor[100] = "unknown";
 	extern char saved_command_line[];
+#ifdef XEN
+	int phys_efi = 0;
+#endif
 	int i;
 
 	/* it's too early to be able to use the standard kernel command line support... */
@@ -434,6 +437,11 @@ efi_init (void)
 			if (end != cp)
 				break;
 			cp = end;
+#ifdef XEN
+		} else if (memcmp(cp, "phys_efi", 8) == 0) {
+			phys_efi = 1;
+			cp+=8;
+#endif
 		} else {
 			while (*cp != ' ' && *cp)
 				++cp;
@@ -527,7 +535,15 @@ efi_init (void)
 #endif
 
 	efi_map_pal_code();
+#ifndef XEN
 	efi_enter_virtual_mode();
+#else
+	if (phys_efi)
+		printk("Forcing EFI to stay in physical mode\n");
+	else
+		efi_enter_virtual_mode();
+#endif
+
 }
 
 void
@@ -600,6 +616,9 @@ efi_enter_virtual_mode (void)
 	efi.set_variable = virt_set_variable;
 	efi.get_next_high_mono_count = virt_get_next_high_mono_count;
 	efi.reset_system = virt_reset_system;
+#ifdef XEN
+	efi.mapped = 1;
+#endif
 }
 
 /*
--- /dev/null
+++ x/xen/arch/ia64/linux-xen/sal_stub.S
@@ -0,0 +1,100 @@
+/*
+ * SAL call stub.
+ *
+ * Copyright (C) 2006 Simon Horman <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 SAL routine
+ *	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
+	;;
+#ifdef XEN
+	dep r2=0,r2,60,4		// __pa
+#else
+	dep r2=0,r2,61,3		// __pa
+#endif
+	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
+	;;
+#ifdef XEN
+	dep gp=0,gp,60,4		// __pa
+#else
+	dep gp=0,gp,61,3		// __pa
+#endif
+	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)
+
--- x/xen/include/asm-ia64/linux-xen/linux/efi.h
+++ x/xen/include/asm-ia64/linux-xen/linux/efi.h
@@ -273,6 +273,7 @@ extern struct efi {
 	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
--- x/xen/include/asm-ia64/linux/asm/sal.h
+++ x/xen/include/asm-ia64/linux/asm/sal.h
@@ -45,9 +45,34 @@
 
 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. */
+struct ia64_sal_retval sal_call_phys(ia64_sal_handler ia64_sal, ...);
+
+#ifdef XEN
+#define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)			\
+	result = efi.mapped ? 						\
+		 (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7) :			\
+		 sal_call_phys(ia64_sal,a0,a1,a2,a3,a4,a5,a6,a7);
+#else
 #define __SAL_CALL(result,a0,a1,a2,a3,a4,a5,a6,a7)	\
-	result = (*ia64_sal)(a0,a1,a2,a3,a4,a5,a6,a7)
+	result = (*ia64_sal)(ia64_sal,a0,a1,a2,a3,a4,a5,a6,a7);
+#endif
 
 # define SAL_CALL(result,args...) do {				\
 	unsigned long __ia64_sc_flags;				\
@@ -95,22 +120,6 @@ extern spinlock_t sal_lock;
 
 #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,
