// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Xilinx, Inc. */ #include #include #include #include #include #include #include #include #include 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; }