1// SPDX-License-Identifier: GPL-2.0+ 2/* 3 * Copyright (C) 2018 Xilinx, Inc. 4 */ 5 6#include <common.h> 7#include <log.h> 8#include <part.h> 9#include <asm/global_data.h> 10#include <asm/io.h> 11#include <asm/arch/hardware.h> 12#include <asm/arch/sys_proto.h> 13#include <u-boot/md5.h> 14#include <zynq_bootimg.h> 15 16DECLARE_GLOBAL_DATA_PTR; 17 18#define ZYNQ_IMAGE_PHDR_OFFSET 0x09C 19#define ZYNQ_IMAGE_FSBL_LEN_OFFSET 0x040 20#define ZYNQ_PART_HDR_CHKSUM_WORD_COUNT 0x0F 21#define ZYNQ_PART_HDR_WORD_COUNT 0x10 22#define ZYNQ_MAXIMUM_IMAGE_WORD_LEN 0x40000000 23#define MD5_CHECKSUM_SIZE 16 24 25struct headerarray { 26 u32 fields[16]; 27}; 28 29/* 30 * Check whether the given partition is last partition or not 31 */ 32static int zynq_islastpartition(struct headerarray *head) 33{ 34 int index; 35 36 debug("%s\n", __func__); 37 if (head->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != 0xFFFFFFFF) 38 return -1; 39 40 for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT - 1; index++) { 41 if (head->fields[index] != 0x0) 42 return -1; 43 } 44 45 return 0; 46} 47 48/* 49 * Get the partition count from the partition header 50 */ 51int zynq_get_part_count(struct partition_hdr *part_hdr_info) 52{ 53 u32 count; 54 struct headerarray *hap; 55 56 debug("%s\n", __func__); 57 58 for (count = 0; count < ZYNQ_MAX_PARTITION_NUMBER; count++) { 59 hap = (struct headerarray *)&part_hdr_info[count]; 60 if (zynq_islastpartition(hap) != -1) 61 break; 62 } 63 64 return count; 65} 66 67/* 68 * Get the partition info of all the partitions available. 69 */ 70int zynq_get_partition_info(u32 image_base_addr, u32 *fsbl_len, 71 struct partition_hdr *part_hdr) 72{ 73 u32 parthdroffset; 74 75 *fsbl_len = *((u32 *)(image_base_addr + ZYNQ_IMAGE_FSBL_LEN_OFFSET)); 76 77 parthdroffset = *((u32 *)(image_base_addr + ZYNQ_IMAGE_PHDR_OFFSET)); 78 79 parthdroffset += image_base_addr; 80 81 memcpy(part_hdr, (u32 *)parthdroffset, 82 (sizeof(struct partition_hdr) * ZYNQ_MAX_PARTITION_NUMBER)); 83 84 return 0; 85} 86 87/* 88 * Check whether the partition header is valid or not 89 */ 90int zynq_validate_hdr(struct partition_hdr *header) 91{ 92 struct headerarray *hap; 93 u32 index; 94 u32 checksum; 95 96 debug("%s\n", __func__); 97 98 hap = (struct headerarray *)header; 99 100 for (index = 0; index < ZYNQ_PART_HDR_WORD_COUNT; index++) { 101 if (hap->fields[index]) 102 break; 103 } 104 if (index == ZYNQ_PART_HDR_WORD_COUNT) 105 return -1; 106 107 checksum = 0; 108 for (index = 0; index < ZYNQ_PART_HDR_CHKSUM_WORD_COUNT; index++) 109 checksum += hap->fields[index]; 110 111 checksum ^= 0xFFFFFFFF; 112 113 if (hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT] != checksum) { 114 printf("Error: Checksum 0x%8.8x != 0x%8.8x\n", 115 checksum, hap->fields[ZYNQ_PART_HDR_CHKSUM_WORD_COUNT]); 116 return -1; 117 } 118 119 if (header->imagewordlen > ZYNQ_MAXIMUM_IMAGE_WORD_LEN) { 120 printf("INVALID_PARTITION_LENGTH\n"); 121 return -1; 122 } 123 124 return 0; 125} 126 127/* 128 * Validate the partition by calculationg the md5 checksum for the 129 * partition and compare with checksum present in checksum offset of 130 * partition 131 */ 132int zynq_validate_partition(u32 start_addr, u32 len, u32 chksum_off) 133{ 134 u8 checksum[MD5_CHECKSUM_SIZE]; 135 u8 calchecksum[MD5_CHECKSUM_SIZE]; 136 137 memcpy(&checksum[0], (u32 *)chksum_off, MD5_CHECKSUM_SIZE); 138 139 md5_wd((u8 *)start_addr, len, &calchecksum[0], 0x10000); 140 141 if (!memcmp(checksum, calchecksum, MD5_CHECKSUM_SIZE)) 142 return 0; 143 144 printf("Error: Partition DataChecksum\n"); 145 return -1; 146} 147