1 /* baytrail_sst_elf_firmware_convert - convert elf SST firmwares to new format
 
   3  * Copyright (C) 2015  Antonio Ospite <ao2@ao2.it>
 
   5  * This program is free software: you can redistribute it and/or modify
 
   6  * it under the terms of the GNU General Public License as published by
 
   7  * the Free Software Foundation, either version 3 of the License, or
 
   8  * (at your option) any later version.
 
  10  * This program is distributed in the hope that it will be useful,
 
  11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
 
  12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
  13  * GNU General Public License for more details.
 
  15  * You should have received a copy of the GNU General Public License
 
  16  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
  22 #include <sys/types.h>
 
  31 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))
 
  34 #define SST_BYT_IRAM_ADDRESS 0xff2c0000
 
  35 #define SST_BYT_DRAM_ADDRESS 0xff300000
 
  36 #define SST_BYT_DDR_ADDRESS 0xc0000000
 
  38 struct sst_ram_region {
 
  41         uint32_t start_address;
 
  44 static struct sst_ram_region ram_regions[] = {
 
  45         { "IRAM", 1, SST_BYT_IRAM_ADDRESS },
 
  46         { "DRAM", 2, SST_BYT_DRAM_ADDRESS },
 
  47         { "DDR", 5, SST_BYT_DDR_ADDRESS },
 
  50 static inline void fwrite_le32(uint32_t x, FILE *file)
 
  52         uint32_t tmp = htole32(x);
 
  53         fwrite(&tmp, sizeof(tmp), 1, file);
 
  56 static struct sst_ram_region *phdr_to_sst_ram_region(GElf_Phdr *phdr)
 
  61         if (phdr->p_type == PT_LOAD && phdr->p_filesz != 0) {
 
  64                 for (i = 0; i < ARRAY_SIZE(ram_regions); i++) {
 
  65                         struct sst_ram_region *r = &ram_regions[i];
 
  67                         if ((phdr->p_vaddr & r->start_address) == r->start_address)
 
  76  * TODO: introduce data structures to represent the firmware headers and
 
  77  * separate the firmware contruction from saving it to a file.
 
  79  * This way the elf file can be scanned just once.
 
  81 static int convert_elf_to_sst_firmware(Elf *elf, FILE *output_file)
 
  85         unsigned int phdr_index;
 
  86         unsigned int num_sst_blocks;
 
  87         unsigned int sst_blocks_total_size;
 
  91         ret = elf_getphdrnum(elf, &num_phdrs);
 
  93                 fprintf(stderr, "Cannot get number of program headers: %s\n",
 
  94                         elf_errmsg(elf_errno()));
 
  99          * Perform a first scan just to see how many SST blocks there are and
 
 100          * how much space they take..
 
 102          * Knowing this info before writing the firmware allows to write the
 
 103          * firmware incrementally without going back to amend the headers to
 
 104          * fill the number of blocks and the module and file sizes.
 
 107         sst_blocks_total_size = 0;
 
 108         for (phdr_index = 0; phdr_index < num_phdrs; ++phdr_index) {
 
 111                 struct sst_ram_region *r;
 
 113                 retp = gelf_getphdr(elf, phdr_index, &phdr);
 
 115                         fprintf(stderr, "gelf_getphdr() failed: %s.",
 
 116                                 elf_errmsg(elf_errno()));
 
 120                 r = phdr_to_sst_ram_region(&phdr);
 
 122                         unsigned int pre_padding = 0;
 
 124                         sst_blocks_total_size += phdr.p_filesz;
 
 127                         if ((phdr.p_vaddr % 16) != 0) {
 
 128                                 pre_padding = 16 - (phdr.p_vaddr % 16);
 
 129                                 fprintf(stderr, "pre_padding: %d\n", pre_padding);
 
 130                                 sst_blocks_total_size += pre_padding;
 
 134                         /* align to multiple of 4 */
 
 135                         if (((phdr.p_filesz + pre_padding) % 4) != 0) {
 
 136                                 unsigned int post_padding = 4 - ((phdr.p_filesz + pre_padding) % 4);
 
 137                                 fprintf(stderr, "filesz: %ld\n", phdr.p_filesz);
 
 138                                 fprintf(stderr, "post_padding: %d\n", post_padding);
 
 139                                 sst_blocks_total_size += post_padding;
 
 144         fprintf(stderr, "Number of SST blocks: %d\n", num_sst_blocks);
 
 145         fprintf(stderr, "SST blocks total size: %d\n", sst_blocks_total_size);
 
 147         data = elf_rawfile(elf, &data_size);
 
 149                 fprintf(stderr, "Cannot get raw file contents: %s\n",
 
 150                         elf_errmsg(elf_errno()));
 
 154         /* start writing the SST firmware file */
 
 155         fwrite("$SST\n", 1, 4, output_file);
 
 157         /* file size: add blocks and module headers sizes */
 
 158         fwrite_le32(sst_blocks_total_size + num_sst_blocks * 16 + 20, output_file);
 
 161         fwrite_le32(1, output_file);
 
 164         fwrite_le32(256, output_file);
 
 167         fwrite_le32(0, output_file);
 
 168         fwrite_le32(0, output_file);
 
 169         fwrite_le32(0, output_file);
 
 170         fwrite_le32(0, output_file);
 
 172         /* start writing the SST module */
 
 173         fwrite("$SST\n", 1, 4, output_file);
 
 175         /* module size: add blocks headers sizes */
 
 176         fwrite_le32(sst_blocks_total_size + num_sst_blocks * 16, output_file);
 
 179         fwrite_le32(num_sst_blocks, output_file);
 
 182         fwrite_le32(65535, output_file);
 
 185         fwrite_le32(0, output_file);
 
 187         for (phdr_index = 0; phdr_index < num_phdrs; ++phdr_index) {
 
 190                 struct sst_ram_region *r;
 
 192                 retp = gelf_getphdr(elf, phdr_index, &phdr);
 
 194                         fprintf(stderr, "gelf_getphdr() failed: %s.",
 
 195                                 elf_errmsg(elf_errno()));
 
 199                 r = phdr_to_sst_ram_region(&phdr);
 
 203                         unsigned int pre_padding = 0;
 
 204                         unsigned int post_padding = 0;
 
 205                         const uint8_t zero = 0;
 
 209                         if ((phdr.p_vaddr % 16) != 0)
 
 210                                 pre_padding = 16 - (phdr.p_vaddr % 16);
 
 213                         if (((phdr.p_filesz + pre_padding) % 4) != 0)
 
 214                                 post_padding = 4 - ((phdr.p_filesz + pre_padding) % 4);
 
 216                         ram_offset = (phdr.p_vaddr & ~r->start_address) - pre_padding;
 
 217                         block_size = phdr.p_filesz + pre_padding + post_padding;
 
 219                         fprintf(stderr, "%s, id: %d, offset: 0x%08x\n", r->name, r->id, ram_offset);
 
 220                         fprintf(stderr, "vaddr: 0x%08lx paddr: 0x%08lx\n", phdr.p_vaddr, phdr.p_paddr);
 
 221                         fprintf(stderr, "alignment: %ld\n", phdr.p_align);
 
 222                         fprintf(stderr, "block_size: %d\n", block_size);
 
 225                         fwrite_le32(r->id, output_file);
 
 228                         fwrite_le32(block_size, output_file);
 
 231                         fwrite_le32(ram_offset, output_file);
 
 234                         fwrite_le32(0, output_file);
 
 237                         for (i = 0; i < pre_padding; i++)
 
 238                                 fwrite(&zero, sizeof(zero), 1, output_file);
 
 241                         fwrite(data + phdr.p_offset, phdr.p_filesz, 1, output_file);
 
 244                         for (i = 0; i < post_padding; i++)
 
 245                                 fwrite(&zero, sizeof(zero), 1, output_file);
 
 252 int main(int argc, char *argv[])
 
 256         unsigned int version;
 
 262                 fprintf(stderr, "usage: %s <elf_file> <output_file>\n", argv[0]);
 
 266         version = elf_version(EV_CURRENT);
 
 267         if (version == EV_NONE) {
 
 268                 fprintf(stderr, "Cannot initialize ELF library: %s\n",
 
 269                         elf_errmsg(elf_errno()));
 
 273         fd = open(argv[1], O_RDONLY);
 
 275                 fprintf(stderr, "Cannot open \"%s\": %s", argv[1],
 
 280         elf = elf_begin(fd, ELF_C_READ, NULL);
 
 282                 fprintf(stderr, "Cannot initialize ELF descriptor: %s.",
 
 283                         elf_errmsg(elf_errno()));
 
 287         kind = elf_kind(elf);
 
 288         if (kind != ELF_K_ELF) {
 
 289                 fprintf(stderr, "\"%s\" is not an ELF file.\n", argv[1]);
 
 293         output_file = fopen(argv[2], "wb");
 
 294         if (output_file == NULL) {
 
 295                 fprintf(stderr, "Cannot open output file \"%s\": %s", argv[1],
 
 300         ret = convert_elf_to_sst_firmware(elf, output_file);
 
 302                 fprintf(stderr, "Cannot convert elf to SST firmware file\n");