1*91f16700Schasinglulu /* 2*91f16700Schasinglulu * Copyright (c) 2017 - 2020, Broadcom 3*91f16700Schasinglulu * 4*91f16700Schasinglulu * SPDX-License-Identifier: BSD-3-Clause 5*91f16700Schasinglulu */ 6*91f16700Schasinglulu 7*91f16700Schasinglulu #include <string.h> 8*91f16700Schasinglulu 9*91f16700Schasinglulu #include <arch_helpers.h> 10*91f16700Schasinglulu #include <common/debug.h> 11*91f16700Schasinglulu 12*91f16700Schasinglulu /* MCU binary image structure: <header> <data> 13*91f16700Schasinglulu * 14*91f16700Schasinglulu * Header structure: 15*91f16700Schasinglulu * <magic-start> 16*91f16700Schasinglulu * <num-sections> 17*91f16700Schasinglulu * {<src-offset> <src-size> <dst-addr>}* 18*91f16700Schasinglulu * <magic-end> 19*91f16700Schasinglulu * 20*91f16700Schasinglulu * MCU data (<data>) consists of several sections of code/data, to be 21*91f16700Schasinglulu * installed (copied) into MCU memories. 22*91f16700Schasinglulu * Header (<header>) gives information about sections contained in <data>. 23*91f16700Schasinglulu * 24*91f16700Schasinglulu * The installer code iterates over sections in MCU binary. 25*91f16700Schasinglulu * For each section, it copies the section into MCU memory. 26*91f16700Schasinglulu * 27*91f16700Schasinglulu * The header contains: 28*91f16700Schasinglulu * - <magic-start> - 32-bit magic number to mark header start 29*91f16700Schasinglulu * - <num-sections> - number of sections in <data> 30*91f16700Schasinglulu * - <num-sections> tuples. Each tuple describes a section. 31*91f16700Schasinglulu * A tuple contains three 32-bit words. 32*91f16700Schasinglulu * - <magic-end> - 32-bit magic number to mark header end 33*91f16700Schasinglulu * 34*91f16700Schasinglulu * Each section is describes by a tuple, consisting of three 32-bit words: 35*91f16700Schasinglulu * - offset of section within MCU binary (relative to beginning of <data>) 36*91f16700Schasinglulu * - section size (in bytes) in MCU binary 37*91f16700Schasinglulu * - target address (in MCU memory). Section is copied to this location. 38*91f16700Schasinglulu * 39*91f16700Schasinglulu * All fields are 32-bit unsigned integers in little endian format. 40*91f16700Schasinglulu * All sizes are assumed to be 32-bit aligned. 41*91f16700Schasinglulu */ 42*91f16700Schasinglulu 43*91f16700Schasinglulu #define SCP_BIN_HEADER_MAGIC_START 0xfa587D01 44*91f16700Schasinglulu #define SCP_BIN_HEADER_MAGIC_END 0xf3e06a85 45*91f16700Schasinglulu 46*91f16700Schasinglulu int download_scp_patch(void *image, unsigned int image_size) 47*91f16700Schasinglulu { 48*91f16700Schasinglulu unsigned int *pheader = (unsigned int *)(image); 49*91f16700Schasinglulu unsigned int header_size; 50*91f16700Schasinglulu unsigned char *pdata; 51*91f16700Schasinglulu void *dest; 52*91f16700Schasinglulu unsigned int num_sections; 53*91f16700Schasinglulu unsigned int section_src_offset; 54*91f16700Schasinglulu unsigned int section_size; 55*91f16700Schasinglulu 56*91f16700Schasinglulu if (pheader && (pheader[0] != SCP_BIN_HEADER_MAGIC_START)) { 57*91f16700Schasinglulu ERROR("SCP: Could not find SCP header.\n"); 58*91f16700Schasinglulu return -1; 59*91f16700Schasinglulu } 60*91f16700Schasinglulu 61*91f16700Schasinglulu num_sections = pheader[1]; 62*91f16700Schasinglulu INFO("...Number of sections: %d\n", num_sections); 63*91f16700Schasinglulu header_size = 4 * (1 + 1 + 3 * num_sections + 1); 64*91f16700Schasinglulu 65*91f16700Schasinglulu if (image_size < header_size) { 66*91f16700Schasinglulu ERROR("SCP: Wrong size.\n"); 67*91f16700Schasinglulu return -1; 68*91f16700Schasinglulu } 69*91f16700Schasinglulu 70*91f16700Schasinglulu if (*(pheader + header_size/4 - 1) != SCP_BIN_HEADER_MAGIC_END) { 71*91f16700Schasinglulu ERROR("SCP: Could not find SCP footer.\n"); 72*91f16700Schasinglulu return -1; 73*91f16700Schasinglulu } 74*91f16700Schasinglulu 75*91f16700Schasinglulu VERBOSE("SCP image header validated successfully\n"); 76*91f16700Schasinglulu pdata = (unsigned char *)pheader + header_size; 77*91f16700Schasinglulu 78*91f16700Schasinglulu for (pheader += 2; num_sections > 0; num_sections--) { 79*91f16700Schasinglulu 80*91f16700Schasinglulu section_src_offset = pheader[0]; 81*91f16700Schasinglulu section_size = pheader[1]; 82*91f16700Schasinglulu dest = (void *)(unsigned long)pheader[2]; 83*91f16700Schasinglulu 84*91f16700Schasinglulu INFO("section: src:0x%x, size:%d, dst:0x%x\n", 85*91f16700Schasinglulu section_src_offset, section_size, pheader[2]); 86*91f16700Schasinglulu 87*91f16700Schasinglulu if ((section_src_offset + section_size) > image_size) { 88*91f16700Schasinglulu ERROR("SCP: Section points to outside of patch.\n"); 89*91f16700Schasinglulu return -1; 90*91f16700Schasinglulu } 91*91f16700Schasinglulu 92*91f16700Schasinglulu /* copy from source to target section */ 93*91f16700Schasinglulu memcpy(dest, pdata + section_src_offset, section_size); 94*91f16700Schasinglulu flush_dcache_range((uintptr_t)dest, section_size); 95*91f16700Schasinglulu 96*91f16700Schasinglulu /* next section */ 97*91f16700Schasinglulu pheader += 3; 98*91f16700Schasinglulu } 99*91f16700Schasinglulu return 0; 100*91f16700Schasinglulu } 101