aboot: add support for booting 64bit kernel

Dynamically check weather a given bootimage contains
a 64bit kernel and add support for booting into the 64bit
kernel via secure-monitor(EL3) api.

Change-Id: Ifcc63181258df561d8acdd7ce2374a75113f357a
diff --git a/app/aboot/aboot.c b/app/aboot/aboot.c
index f82a2b3..589ffd2 100755
--- a/app/aboot/aboot.c
+++ b/app/aboot/aboot.c
@@ -102,6 +102,8 @@
 #define UBI_MAGIC      "UBI#"
 #define UBI_MAGIC_SIZE 0x04
 
+#define IS_ARM64(ptr) (ptr->magic_64 == KERNEL64_HDR_MAGIC) ? true : false
+
 #if UFS_SUPPORT
 static const char *emmc_cmdline = " androidboot.bootdevice=msm_sdcc.1";
 static const char *ufs_cmdline = " androidboot.bootdevice=msm_ufs.1";
@@ -181,11 +183,14 @@
 extern int fastboot_trigger(void);
 #endif
 
-static void update_ker_tags_rdisk_addr(struct boot_img_hdr *hdr)
+static void update_ker_tags_rdisk_addr(struct boot_img_hdr *hdr, bool is_arm64)
 {
 	/* overwrite the destination of specified for the project */
 #ifdef ABOOT_IGNORE_BOOT_HEADER_ADDRS
-	hdr->kernel_addr = ABOOT_FORCE_KERNEL_ADDR;
+	if (is_arm64)
+		hdr->kernel_addr = ABOOT_FORCE_KERNEL64_ADDR;
+	else
+		hdr->kernel_addr = ABOOT_FORCE_KERNEL_ADDR;
 	hdr->ramdisk_addr = ABOOT_FORCE_RAMDISK_ADDR;
 	hdr->tags_addr = ABOOT_FORCE_TAGS_ADDR;
 #endif
@@ -579,6 +584,7 @@
 
 	void (*entry)(unsigned, unsigned, unsigned*) = (entry_func_ptr*)(PA((addr_t)kernel));
 	uint32_t tags_phys = PA((addr_t)tags);
+	struct kernel64_hdr *kptr = (struct kernel64_hdr*)kernel;
 
 	ramdisk = PA(ramdisk);
 
@@ -623,7 +629,13 @@
 	arch_disable_mmu();
 #endif
 	bs_set_timestamp(BS_KERNEL_ENTRY);
-	entry(0, machtype, (unsigned*)tags_phys);
+
+	if (IS_ARM64(kptr))
+		/* Jump to a 64bit kernel */
+		scm_elexec_call((paddr_t)kernel, tags_phys);
+	else
+		/* Jump to a 32bit kernel */
+		entry(0, machtype, (unsigned*)tags_phys);
 }
 
 /* Function to check if the memory address range falls within the aboot
@@ -648,9 +660,9 @@
 
 #define ROUND_TO_PAGE(x,y) (((x) + (y)) & (~(y)))
 
-BUF_DMA_ALIGN(buf, 4096); //Equal to max-supported pagesize
+BUF_DMA_ALIGN(buf, BOOT_IMG_MAX_PAGE_SIZE); //Equal to max-supported pagesize
 #if DEVICE_TREE
-BUF_DMA_ALIGN(dt_buf, 4096);
+BUF_DMA_ALIGN(dt_buf, BOOT_IMG_MAX_PAGE_SIZE);
 #endif
 
 static void verify_signed_bootimg(uint32_t bootimg_addr, uint32_t bootimg_size)
@@ -763,6 +775,9 @@
 	uint32_t dt_actual;
 	uint32_t dt_hdr_size;
 #endif
+	BUF_DMA_ALIGN(kbuf, BOOT_IMG_MAX_PAGE_SIZE);
+	struct kernel64_hdr *kptr = (void*) kbuf;
+
 	if (check_format_bit())
 		boot_into_recovery = 1;
 
@@ -815,12 +830,21 @@
 		page_mask = page_size - 1;
 	}
 
+	/* Read the next page to get kernel Image header
+	 * which lives in the second page for arm64 targets.
+	 */
+
+	if (mmc_read(ptn + page_size, (unsigned int *) kbuf, page_size)) {
+		dprintf(CRITICAL, "ERROR: Cannot read boot image header\n");
+                return -1;
+	}
+
 	/*
 	 * Update the kernel/ramdisk/tags address if the boot image header
 	 * has default values, these default values come from mkbootimg when
 	 * the boot image is flashed using fastboot flash:raw
 	 */
-	update_ker_tags_rdisk_addr(hdr);
+	update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr));
 
 	/* Get virtual addresses since the hdr saves physical addresses. */
 	hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
@@ -1141,7 +1165,7 @@
 	 * has default values, these default values come from mkbootimg when
 	 * the boot image is flashed using fastboot flash:raw
 	 */
-	update_ker_tags_rdisk_addr(hdr);
+	update_ker_tags_rdisk_addr(hdr, false);
 
 	/* Get virtual addresses since the hdr saves physical addresses. */
 	hdr->kernel_addr = VA((addr_t)(hdr->kernel_addr));
@@ -1327,7 +1351,7 @@
 	return 0;
 }
 
-BUF_DMA_ALIGN(info_buf, 4096);
+BUF_DMA_ALIGN(info_buf, BOOT_IMG_MAX_PAGE_SIZE);
 void write_device_info_mmc(device_info *dev)
 {
 	struct device_info *info = (void*) info_buf;
@@ -1565,6 +1589,7 @@
 	unsigned kernel_actual;
 	unsigned ramdisk_actual;
 	struct boot_img_hdr *hdr;
+	struct kernel64_hdr *kptr;
 	char *ptr = ((char*) data);
 	int ret = 0;
 	uint8_t dtb_copied = 0;
@@ -1592,7 +1617,8 @@
 	 * has default values, these default values come from mkbootimg when
 	 * the boot image is flashed using fastboot flash:raw
 	 */
-	update_ker_tags_rdisk_addr(hdr);
+	kptr = (struct kernel64_hdr*)((char*) data + page_size);
+	update_ker_tags_rdisk_addr(hdr, IS_ARM64(kptr));
 
 	/* Get virtual addresses since the hdr saves physical addresses. */
 	hdr->kernel_addr = VA(hdr->kernel_addr);
diff --git a/app/aboot/bootimg.h b/app/aboot/bootimg.h
index f9966a1..8320470 100644
--- a/app/aboot/bootimg.h
+++ b/app/aboot/bootimg.h
@@ -2,6 +2,8 @@
  * Copyright (C) 2008 The Android Open Source Project
  * All rights reserved.
  *
+ * Copyright (c) 2014, The Linux Foundation. All rights reserved.
+ *
  * Redistribution and use in source and binary forms, with or without
  * modification, are permitted provided that the following conditions
  * are met:
@@ -33,8 +35,9 @@
 
 #define BOOT_MAGIC "ANDROID!"
 #define BOOT_MAGIC_SIZE 8
-#define BOOT_NAME_SIZE 16
-#define BOOT_ARGS_SIZE 512
+#define BOOT_NAME_SIZE  16
+#define BOOT_ARGS_SIZE  512
+#define BOOT_IMG_MAX_PAGE_SIZE 4096
 
 struct boot_img_hdr
 {
@@ -97,4 +100,21 @@
                         unsigned *bootimg_size);
 
 void bootimg_set_cmdline(boot_img_hdr *hdr, const char *cmdline);                
+
+#define KERNEL64_HDR_MAGIC 0x644D5241 /* ARM64 */
+
+struct kernel64_hdr
+{
+    uint32_t insn;
+    uint32_t res1;
+    uint64_t text_offset;
+    uint64_t res2;
+    uint64_t res3;
+    uint64_t res4;
+    uint64_t res5;
+    uint64_t res6;
+    uint32_t magic_64;
+    uint32_t res7;
+};
+
 #endif
diff --git a/project/apq8084.mk b/project/apq8084.mk
index 7cd843f..2905eff 100644
--- a/project/apq8084.mk
+++ b/project/apq8084.mk
@@ -24,6 +24,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00008000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 ifeq ($(EMMC_BOOT),1)
 DEFINES += _EMMC_BOOT=1
diff --git a/project/fsm9900.mk b/project/fsm9900.mk
index 2745b63..62ef109 100644
--- a/project/fsm9900.mk
+++ b/project/fsm9900.mk
@@ -24,6 +24,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00008000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 ifeq ($(EMMC_BOOT),1)
 DEFINES += _EMMC_BOOT=1
diff --git a/project/mpq8092.mk b/project/mpq8092.mk
index 36be395..c5bab96 100644
--- a/project/mpq8092.mk
+++ b/project/mpq8092.mk
@@ -20,6 +20,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00008000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 ifeq ($(ENABLE_SDHCI_SUPPORT),1)
 DEFINES += MMC_SDHCI_SUPPORT=1
diff --git a/project/msm8226.mk b/project/msm8226.mk
index f41a778..a165ec1 100644
--- a/project/msm8226.mk
+++ b/project/msm8226.mk
@@ -26,6 +26,7 @@
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
 DEFINES += IMAGE_VERIF_ALGO_SHA1=0
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 #Disable thumb mode
 ENABLE_THUMB := false
diff --git a/project/msm8610.mk b/project/msm8610.mk
index 5bcad33..03c15ea 100644
--- a/project/msm8610.mk
+++ b/project/msm8610.mk
@@ -25,6 +25,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00008000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 #Disable thumb mode
 #TODO: The gold linker has issues generating correct
diff --git a/project/msm8916.mk b/project/msm8916.mk
index 806082b..5dee988 100644
--- a/project/msm8916.mk
+++ b/project/msm8916.mk
@@ -18,6 +18,7 @@
 DEFINES += ABOOT_IGNORE_BOOT_HEADER_ADDRS=1
 
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x80008000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x80080000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x82000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x81E00000
 
diff --git a/project/msm8974.mk b/project/msm8974.mk
index b12ea6b..a6ca245 100644
--- a/project/msm8974.mk
+++ b/project/msm8974.mk
@@ -26,6 +26,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00008000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 ifeq ($(EMMC_BOOT),1)
 DEFINES += _EMMC_BOOT=1
diff --git a/project/plutonium.mk b/project/plutonium.mk
index b343a5d..4cb9cb2 100644
--- a/project/plutonium.mk
+++ b/project/plutonium.mk
@@ -20,6 +20,7 @@
 DEFINES += ABOOT_FORCE_KERNEL_ADDR=0x00080000
 DEFINES += ABOOT_FORCE_RAMDISK_ADDR=0x02000000
 DEFINES += ABOOT_FORCE_TAGS_ADDR=0x01e00000
+DEFINES += ABOOT_FORCE_KERNEL64_ADDR=0x00080000
 
 #Disable thumb mode
 ENABLE_THUMB := false