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");