xilinx: zynq: Add support to secure images

This patch basically adds two new commands for loadig secure
images.
1. zynq rsa adds support to load secure image which can be both
   authenticated or encrypted or both authenticated and encrypted
   image in xilinx bootimage(BOOT.bin) format.
2. zynq aes command adds support to decrypt and load encrypted
   image back to DDR as per destination address. The image has
   to be encrypted using xilinx bootgen tool and to get only the
   encrypted image from tool use -split option while invoking
   bootgen.

Signed-off-by: Siva Durga Prasad Paladugu <siva.durga.paladugu@xilinx.com>
Signed-off-by: Michal Simek <michal.simek@xilinx.com>
diff --git a/board/xilinx/zynq/bootimg.c b/board/xilinx/zynq/bootimg.c
new file mode 100644
index 0000000..56d69cd
--- /dev/null
+++ b/board/xilinx/zynq/bootimg.c
@@ -0,0 +1,143 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Xilinx, Inc.
+ */
+
+#include <common.h>
+#include <asm/io.h>
+#include <asm/arch/hardware.h>
+#include <asm/arch/sys_proto.h>
+#include <u-boot/md5.h>
+#include <zynq_bootimg.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+#define ZYNQ_IMAGE_PHDR_OFFSET		0x09C
+#define ZYNQ_IMAGE_FSBL_LEN_OFFSET	0x040
+#define ZYNQ_PART_HDR_CHKSUM_WORD_COUNT	0x0F
+#define ZYNQ_PART_HDR_WORD_COUNT	0x10
+#define ZYNQ_MAXIMUM_IMAGE_WORD_LEN	0x40000000
+#define MD5_CHECKSUM_SIZE	16
+
+struct headerarray {
+	u32 fields[16];
+};
+
+/*
+ * Check whether the given partition is last partition or not
+ */
+static int zynq_islastpartition(struct headerarray *head)
+{
+	int index;
+
+	debug("%s\n", __func__);
+	if (head->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != 0xFFFFFFFF)
+		return -1;
+
+	for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT - 1; index++) {
+		if (head->fields[index] != 0x0)
+			return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Get the partition count from the partition header
+ */
+int zynq_get_part_count(struct partition_hdr *part_hdr_info)
+{
+	u32 count;
+	struct headerarray *hap;
+
+	debug("%s\n", __func__);
+
+	for (count = 0; count < ZYNQ_MAX_PARTITION_NUMBER; count++) {
+		hap = (struct headerarray *)&part_hdr_info[count];
+		if (zynq_islastpartition(hap) != -1)
+			break;
+	}
+
+	return count;
+}
+
+/*
+ * Get the partition info of all the partitions available.
+ */
+int zynq_get_partition_info(u32 image_base_addr, u32 *fsbl_len,
+			    struct partition_hdr *part_hdr)
+{
+	u32 parthdroffset;
+
+	*fsbl_len = *((u32 *)(image_base_addr + ZYNQ_IMAGE_FSBL_LEN_OFFSET));
+
+	parthdroffset = *((u32 *)(image_base_addr + ZYNQ_IMAGE_PHDR_OFFSET));
+
+	parthdroffset += image_base_addr;
+
+	memcpy(part_hdr, (u32 *)parthdroffset,
+	       (sizeof(struct partition_hdr) * ZYNQ_MAX_PARTITION_NUMBER));
+
+	return 0;
+}
+
+/*
+ * Check whether the partition header is valid or not
+ */
+int zynq_validate_hdr(struct partition_hdr *header)
+{
+	struct headerarray *hap;
+	u32 index;
+	u32 checksum;
+
+	debug("%s\n", __func__);
+
+	hap = (struct headerarray *)header;
+
+	for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT; index++) {
+		if (hap->fields[index])
+			break;
+	}
+	if (index == ZYNQ_PART_HDR_WORD_COUNT)
+		return -1;
+
+	checksum = 0;
+	for (index = 0; index < ZYNQ_PART_HDR_CHKSUM_WORD_COUNT; index++)
+		checksum += hap->fields[index];
+
+	checksum ^= 0xFFFFFFFF;
+
+	if (hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != checksum) {
+		printf("Error: Checksum 0x%8.8x != 0x%8.8x\n",
+		       checksum, hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT]);
+		return -1;
+	}
+
+	if (header->imagewordlen > ZYNQ_MAXIMUM_IMAGE_WORD_LEN) {
+		printf("INVALID_PARTITION_LENGTH\n");
+		return -1;
+	}
+
+	return 0;
+}
+
+/*
+ * Validate the partition by calculationg the md5 checksum for the
+ * partition and compare with checksum present in checksum offset of
+ * partition
+ */
+int zynq_validate_partition(u32 start_addr, u32 len, u32 chksum_off)
+{
+	u8 checksum[MD5_CHECKSUM_SIZE];
+	u8 calchecksum[MD5_CHECKSUM_SIZE];
+
+	memcpy(&checksum[0], (u32 *)chksum_off, MD5_CHECKSUM_SIZE);
+
+	md5_wd((u8 *)start_addr, len, &calchecksum[0], 0x10000);
+
+	if (!memcmp(checksum, calchecksum, MD5_CHECKSUM_SIZE))
+		return 0;
+
+	printf("Error: Partition DataChecksum\n");
+	return -1;
+}