1 /* 2 * Copyright (C) 2014 Charles Manning <cdhmanning@gmail.com> 3 * 4 * SPDX-License-Identifier: GPL-2.0+ 5 * 6 * Reference doc http://www.altera.com.cn/literature/hb/cyclone-v/cv_5400A.pdf 7 * Note this doc is not entirely accurate. Of particular interest to us is the 8 * "header" length field being in U32s and not bytes. 9 * 10 * "Header" is a structure of the following format. 11 * this is positioned at 0x40. 12 * 13 * Endian is LSB. 14 * 15 * Offset Length Usage 16 * ----------------------- 17 * 0x40 4 Validation word 0x31305341 18 * 0x44 1 Version (whatever, zero is fine) 19 * 0x45 1 Flags (unused, zero is fine) 20 * 0x46 2 Length (in units of u32, including the end checksum). 21 * 0x48 2 Zero 22 * 0x4A 2 Checksum over the header. NB Not CRC32 23 * 24 * At the end of the code we have a 32-bit CRC checksum over whole binary 25 * excluding the CRC. 26 * 27 * Note that the CRC used here is **not** the zlib/Adler crc32. It is the 28 * CRC-32 used in bzip2, ethernet and elsewhere. 29 * 30 * The image is padded out to 64k, because that is what is 31 * typically used to write the image to the boot medium. 32 */ 33 34 #include "pbl_crc32.h" 35 #include "imagetool.h" 36 #include <image.h> 37 38 #define HEADER_OFFSET 0x40 39 #define VALIDATION_WORD 0x31305341 40 #define PADDED_SIZE 0x10000 41 42 /* To allow for adding CRC, the max input size is a bit smaller. */ 43 #define MAX_INPUT_SIZE (PADDED_SIZE - sizeof(uint32_t)) 44 45 static uint8_t buffer[PADDED_SIZE]; 46 47 static struct socfpga_header { 48 uint32_t validation; 49 uint8_t version; 50 uint8_t flags; 51 uint16_t length_u32; 52 uint16_t zero; 53 uint16_t checksum; 54 } header; 55 56 /* 57 * The header checksum is just a very simple checksum over 58 * the header area. 59 * There is still a crc32 over the whole lot. 60 */ 61 static uint16_t hdr_checksum(struct socfpga_header *header) 62 { 63 int len = sizeof(*header) - sizeof(header->checksum); 64 uint8_t *buf = (uint8_t *)header; 65 uint16_t ret = 0; 66 67 while (--len) 68 ret += *buf++; 69 70 return ret; 71 } 72 73 74 static void build_header(uint8_t *buf, uint8_t version, uint8_t flags, 75 uint16_t length_bytes) 76 { 77 header.validation = htole32(VALIDATION_WORD); 78 header.version = version; 79 header.flags = flags; 80 header.length_u32 = htole16(length_bytes/4); 81 header.zero = 0; 82 header.checksum = htole16(hdr_checksum(&header)); 83 84 memcpy(buf, &header, sizeof(header)); 85 } 86 87 /* 88 * Perform a rudimentary verification of header and return 89 * size of image. 90 */ 91 static int verify_header(const uint8_t *buf) 92 { 93 memcpy(&header, buf, sizeof(header)); 94 95 if (le32toh(header.validation) != VALIDATION_WORD) 96 return -1; 97 if (le16toh(header.checksum) != hdr_checksum(&header)) 98 return -1; 99 100 return le16toh(header.length_u32) * 4; 101 } 102 103 /* Sign the buffer and return the signed buffer size */ 104 static int sign_buffer(uint8_t *buf, 105 uint8_t version, uint8_t flags, 106 int len, int pad_64k) 107 { 108 uint32_t calc_crc; 109 110 /* Align the length up */ 111 len = (len + 3) & (~3); 112 113 /* Build header, adding 4 bytes to length to hold the CRC32. */ 114 build_header(buf + HEADER_OFFSET, version, flags, len + 4); 115 116 /* Calculate and apply the CRC */ 117 calc_crc = ~pbl_crc32(0, (char *)buf, len); 118 119 *((uint32_t *)(buf + len)) = htole32(calc_crc); 120 121 if (!pad_64k) 122 return len + 4; 123 124 return PADDED_SIZE; 125 } 126 127 /* Verify that the buffer looks sane */ 128 static int verify_buffer(const uint8_t *buf) 129 { 130 int len; /* Including 32bit CRC */ 131 uint32_t calc_crc; 132 uint32_t buf_crc; 133 134 len = verify_header(buf + HEADER_OFFSET); 135 if (len < 0) { 136 fprintf(stderr, "Invalid header\n"); 137 return -1; 138 } 139 140 if (len < HEADER_OFFSET || len > PADDED_SIZE) { 141 fprintf(stderr, "Invalid header length (%i)\n", len); 142 return -1; 143 } 144 145 /* 146 * Adjust length to the base of the CRC. 147 * Check the CRC. 148 */ 149 len -= 4; 150 151 calc_crc = ~pbl_crc32(0, (const char *)buf, len); 152 153 buf_crc = le32toh(*((uint32_t *)(buf + len))); 154 155 if (buf_crc != calc_crc) { 156 fprintf(stderr, "CRC32 does not match (%08x != %08x)\n", 157 buf_crc, calc_crc); 158 return -1; 159 } 160 161 return 0; 162 } 163 164 /* mkimage glue functions */ 165 static int socfpgaimage_verify_header(unsigned char *ptr, int image_size, 166 struct image_tool_params *params) 167 { 168 if (image_size != PADDED_SIZE) 169 return -1; 170 171 return verify_buffer(ptr); 172 } 173 174 static void socfpgaimage_print_header(const void *ptr) 175 { 176 if (verify_buffer(ptr) == 0) 177 printf("Looks like a sane SOCFPGA preloader\n"); 178 else 179 printf("Not a sane SOCFPGA preloader\n"); 180 } 181 182 static int socfpgaimage_check_params(struct image_tool_params *params) 183 { 184 /* Not sure if we should be accepting fflags */ 185 return (params->dflag && (params->fflag || params->lflag)) || 186 (params->fflag && (params->dflag || params->lflag)) || 187 (params->lflag && (params->dflag || params->fflag)); 188 } 189 190 static int socfpgaimage_check_image_types(uint8_t type) 191 { 192 if (type == IH_TYPE_SOCFPGAIMAGE) 193 return EXIT_SUCCESS; 194 return EXIT_FAILURE; 195 } 196 197 /* 198 * To work in with the mkimage framework, we do some ugly stuff... 199 * 200 * First, socfpgaimage_vrec_header() is called. 201 * We prepend a fake header big enough to make the file PADDED_SIZE. 202 * This gives us enough space to do what we want later. 203 * 204 * Next, socfpgaimage_set_header() is called. 205 * We fix up the buffer by moving the image to the start of the buffer. 206 * We now have some room to do what we need (add CRC and padding). 207 */ 208 209 static int data_size; 210 #define FAKE_HEADER_SIZE (PADDED_SIZE - data_size) 211 212 static int socfpgaimage_vrec_header(struct image_tool_params *params, 213 struct image_type_params *tparams) 214 { 215 struct stat sbuf; 216 217 if (params->datafile && 218 stat(params->datafile, &sbuf) == 0 && 219 sbuf.st_size <= MAX_INPUT_SIZE) { 220 data_size = sbuf.st_size; 221 tparams->header_size = FAKE_HEADER_SIZE; 222 } 223 return 0; 224 } 225 226 static void socfpgaimage_set_header(void *ptr, struct stat *sbuf, int ifd, 227 struct image_tool_params *params) 228 { 229 uint8_t *buf = (uint8_t *)ptr; 230 231 /* 232 * This function is called after vrec_header() has been called. 233 * At this stage we have the FAKE_HEADER_SIZE dummy bytes followed by 234 * data_size image bytes. Total = PADDED_SIZE. 235 * We need to fix the buffer by moving the image bytes back to 236 * the beginning of the buffer, then actually do the signing stuff... 237 */ 238 memmove(buf, buf + FAKE_HEADER_SIZE, data_size); 239 memset(buf + data_size, 0, FAKE_HEADER_SIZE); 240 241 sign_buffer(buf, 0, 0, data_size, 0); 242 } 243 244 static struct image_type_params socfpgaimage_params = { 245 .name = "Altera SOCFPGA preloader support", 246 .vrec_header = socfpgaimage_vrec_header, 247 .header_size = 0, /* This will be modified by vrec_header() */ 248 .hdr = (void *)buffer, 249 .check_image_type = socfpgaimage_check_image_types, 250 .verify_header = socfpgaimage_verify_header, 251 .print_header = socfpgaimage_print_header, 252 .set_header = socfpgaimage_set_header, 253 .check_params = socfpgaimage_check_params, 254 }; 255 256 void init_socfpga_image_type(void) 257 { 258 register_image_type(&socfpgaimage_params); 259 } 260