bzimage: Fixup for kernel changes to EFI handover protocol

The ABI of the EFI handover protocol was changed in v3.8 with the
following upstream kernel commit,

  : commit f791620fa7517e1045742c475a7f005db9a634b8
  : Author: David Woodhouse <David.Woodhouse@intel.com>
  : Date:   Mon Jan 7 22:01:50 2013 +0000
  :
  :    x86, efi: Fix 32-bit EFI handover protocol entry point

from a 'jmp' to a 'call'. This affects the layout of arguments on the
stack since 'call' expects the return address to be the data item at the
top of the stack.

Signed-off-by: Matt Fleming <matt.fleming@intel.com>
diff --git a/loaders/bzimage/bzimage.c b/loaders/bzimage/bzimage.c
index d683eae..6c992b3 100644
--- a/loaders/bzimage/bzimage.c
+++ b/loaders/bzimage/bzimage.c
@@ -334,7 +334,8 @@
 	 * protocol.
 	 */
 	if (buf->hdr.version >= 0x20b) {
-		handover_jump(image, boot_params, kernel_start);
+		handover_jump(buf->hdr.version, image,
+			      boot_params, kernel_start);
 		goto out;
 	}
 
diff --git a/loaders/bzimage/i386.h b/loaders/bzimage/i386.h
index 593e2af..0b74c80 100644
--- a/loaders/bzimage/i386.h
+++ b/loaders/bzimage/i386.h
@@ -42,19 +42,28 @@
 		      :: "m" (boot_params), "m" (kernel_start));
 }
 
-static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+typedef void(*handover_func)(void *, EFI_SYSTEM_TABLE *,
+			     struct boot_params *) __attribute__((regparm(0)));
+
+static inline void handover_jump(UINT16 kernel_version, EFI_HANDLE image,
+				 struct boot_params *bp,
 				 EFI_PHYSICAL_ADDRESS kernel_start)
 {
 	kernel_start += bp->hdr.handover_offset;
 
-	asm volatile ("cli		\n"
-		      "pushl %0         \n"
-		      "pushl %1         \n"
-		      "pushl %2         \n"
-		      "movl %3, %%ecx	\n"
-		      "jmp *%%ecx	\n"
-		      :: "m" (bp), "m" (ST),
-		         "m" (image), "m" (kernel_start));
+	if (kernel_version == 0x20b) {
+		asm volatile ("cli		\n"
+			      "pushl %0         \n"
+			      "pushl %1         \n"
+			      "pushl %2         \n"
+			      "movl %3, %%ecx	\n"
+			      "jmp *%%ecx	\n"
+			      :: "m" (bp), "m" (ST),
+			      "m" (image), "m" (kernel_start));
+	} else {
+		handover_func hf = (handover_func)(UINTN)kernel_start;
+		hf(image, ST, bp);
+	}
 }
 
 #endif /* __I386_H__ */
diff --git a/loaders/bzimage/x86_64.h b/loaders/bzimage/x86_64.h
index b63710e..e44f7f9 100644
--- a/loaders/bzimage/x86_64.h
+++ b/loaders/bzimage/x86_64.h
@@ -52,7 +52,8 @@
 	kf(NULL, boot_params);
 }
 
-static inline void handover_jump(EFI_HANDLE image, struct boot_params *bp,
+static inline void handover_jump(UINT16 kernel_version, EFI_HANDLE image,
+				 struct boot_params *bp,
 				 EFI_PHYSICAL_ADDRESS kernel_start)
 {
 	UINT32 offset = bp->hdr.handover_offset;