blob: 4068734ea1cc914b875781e27c75cb94404e482a [file] [log] [blame]
Liam Girdwood05ef4342018-02-13 20:29:40 +00001/*
2 * ELF to firmware image creator.
3 *
4 * Copyright (c) 2015, Intel Corporation.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 */
15
16
17#include <stdlib.h>
18#include <stdio.h>
19#include <unistd.h>
20#include <errno.h>
21#include <string.h>
22
23#include "rimage.h"
24#include "file_format.h"
25
26#define BYT_IRAM_BASE 0xff2c0000
27#define BYT_IRAM_HOST_OFFSET 0x0C0000
28#define BYT_IRAM_SIZE (80 * 1024)
29#define BYT_DRAM_BASE 0xff300000
30#define BYT_DRAM_HOST_OFFSET 0x100000
31#define BYT_DRAM_SIZE (160 * 1024)
32
33#define HSW_IRAM_BASE 0x00000000
34#define HSW_IRAM_HOST_OFFSET 0x00080000
35#define HSW_IRAM_SIZE (384 * 1024)
36#define HSW_DRAM_BASE 0x00400000
37#define HSW_DRAM_HOST_OFFSET 0x00000000
38#define HSW_DRAM_SIZE (512 * 1024)
39
40#define BDW_IRAM_BASE 0x00000000
41#define BDW_IRAM_HOST_OFFSET 0x000A0000
42#define BDW_IRAM_SIZE (320 * 1024)
43#define BDW_DRAM_BASE 0x00400000
44#define BDW_DRAM_HOST_OFFSET 0x00000000
45#define BDW_DRAM_SIZE (640 * 1024)
46
47static int is_iram(struct image *image, Elf32_Shdr *section)
48{
49 const struct adsp *adsp = image->adsp;
50 uint32_t start, end;
51
52 start = section->sh_addr;
53 end = section->sh_addr + section->sh_size;
54
55 if (start < adsp->iram_base)
56 return 0;
57 if (start >= adsp->iram_base + adsp->iram_size)
58 return 0;
59 if (end > adsp->iram_base + adsp->iram_size)
60 return 0;
61 return 1;
62}
63
64static int is_dram(struct image *image, Elf32_Shdr *section)
65{
66 const struct adsp *adsp = image->adsp;
67 uint32_t start, end;
68
69 start = section->sh_addr;
70 end = section->sh_addr + section->sh_size;
71
72 if (start < adsp->dram_base)
73 return 0;
74 if (start >= adsp->dram_base + adsp->dram_size)
75 return 0;
76 if (end > adsp->dram_base + adsp->dram_size)
77 return 0;
78 return 1;
79}
80
81static int block_idx;
82
83static int write_block(struct image *image, struct module *module,
84 Elf32_Shdr *section)
85{
86 const struct adsp *adsp = image->adsp;
87 struct snd_sof_blk_hdr block;
88 size_t count;
89 void *buffer;
90 int ret;
91
92 block.size = section->sh_size;
93
94 if (is_iram(image, section)) {
95 block.type = SOF_BLK_TEXT;
96 block.offset = section->sh_addr - adsp->iram_base
97 + adsp->host_iram_offset;
98 } else if (is_dram(image, section)) {
99 block.type = SOF_BLK_DATA;
100 block.offset = section->sh_addr - adsp->dram_base
101 + adsp->host_dram_offset;
102 } else {
103 fprintf(stderr, "error: invalid block address/size 0x%x/0x%x\n",
104 section->sh_addr, section->sh_size);
105 return -EINVAL;
106 }
107
108 /* write header */
109 count = fwrite(&block, sizeof(block), 1, image->out_fd);
110 if (count != 1)
111 return -errno;
112
113 /* alloc data data */
114 buffer = calloc(1, section->sh_size);
115 if (buffer == NULL)
116 return -ENOMEM;
117
118 /* read in section data */
119 ret = fseek(module->fd, section->sh_offset, SEEK_SET);
120 if (ret < 0) {
121 fprintf(stderr, "error: cant seek to section %d\n", ret);
122 goto out;
123 }
124 count = fread(buffer, 1, section->sh_size, module->fd);
125 if (count != section->sh_size) {
126 fprintf(stderr, "error: cant read section %d\n", -errno);
127 ret = -errno;
128 goto out;
129 }
130
131 /* write out section data */
132 count = fwrite(buffer, 1, section->sh_size, image->out_fd);
133 if (count != section->sh_size) {
134 fprintf(stderr, "error: cant write section %d\n", -errno);
135 fprintf(stderr, " foffset %d size 0x%x mem addr 0x%x\n",
136 section->sh_offset, section->sh_size, section->sh_addr);
137 ret = -errno;
138 goto out;
139 }
140
141 fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8lx\t%s\n", block_idx++,
142 section->sh_addr, section->sh_size, ftell(image->out_fd),
143 block.type == SOF_BLK_TEXT ? "TEXT" : "DATA");
144
145out:
146 free(buffer);
147 return ret;
148}
149
150static int simple_write_module(struct image *image, struct module *module)
151{
152 struct snd_sof_mod_hdr hdr;
153 Elf32_Shdr *section;
154 size_t count;
155 int i, err;
156 uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
157
158 hdr.num_blocks = module->num_sections - module->num_bss;
159 hdr.size = module->text_size + module->data_size +
160 sizeof(struct snd_sof_blk_hdr) * hdr.num_blocks;
161 hdr.type = SOF_FW_BASE;
162
163 count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
164 if (count != 1) {
165 fprintf(stderr, "error: failed to write section header %d\n",
166 -errno);
167 return -errno;
168 }
169
170 fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize");
171
172 fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n",
173 module->text_start, module->text_end,
174 module->text_end - module->text_start);
175 fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n",
176 module->data_start, module->data_end,
177 module->data_end - module->data_start);
178 fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ",
179 module->bss_start, module->bss_end,
180 module->bss_end - module->bss_start);
181
182 fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n");
183
184 for (i = 0; i < module->hdr.e_shnum; i++) {
185
186 section = &module->section[i];
187
188 /* only write valid sections */
189 if (!(module->section[i].sh_flags & valid))
190 continue;
191
192 /* dont write bss */
193 if (section->sh_type == SHT_NOBITS)
194 continue;
195
196 err = write_block(image, module, section);
197 if (err < 0) {
198 fprintf(stderr, "error: failed to write section #%d\n", i);
199 return err;
200 }
201 }
202
203 fprintf(stdout, "\n");
204 return 0;
205}
206
Liam Girdwood7db25d82018-04-12 21:07:35 +0100207static int write_block_reloc(struct image *image, struct module *module)
208{
209 struct snd_sof_blk_hdr block;
210 size_t count;
211 void *buffer;
212 int ret;
213
214 block.size = module->file_size;
215 block.type = SOF_BLK_DATA;
216 block.offset = 0;
217
218 /* write header */
219 count = fwrite(&block, sizeof(block), 1, image->out_fd);
220 if (count != 1)
221 return -errno;
222
223 /* alloc data data */
224 buffer = calloc(1, module->file_size);
225 if (!buffer)
226 return -ENOMEM;
227
228 /* read in section data */
229 ret = fseek(module->fd, 0, SEEK_SET);
230 if (ret < 0) {
231 fprintf(stderr, "error: can't seek to section %d\n", ret);
232 goto out;
233 }
234 count = fread(buffer, 1, module->file_size, module->fd);
235 if (count != module->file_size) {
236 fprintf(stderr, "error: can't read section %d\n", -errno);
237 ret = -errno;
238 goto out;
239 }
240
241 /* write out section data */
242 count = fwrite(buffer, 1, module->file_size, image->out_fd);
243 if (count != module->file_size) {
244 fprintf(stderr, "error: can't write section %d\n", -errno);
245 ret = -errno;
246 goto out;
247 }
248
249 fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8lx\t%s\n", block_idx++,
250 0, module->file_size, ftell(image->out_fd),
251 block.type == SOF_BLK_TEXT ? "TEXT" : "DATA");
252
253out:
254 free(buffer);
255 return ret;
256}
257
258static int simple_write_module_reloc(struct image *image, struct module *module)
259{
260 struct snd_sof_mod_hdr hdr;
261 size_t count;
Yan Wang3ad69eb2018-04-16 16:24:30 +0800262 int err;
Liam Girdwood7db25d82018-04-12 21:07:35 +0100263
264 hdr.num_blocks = 1;
265 hdr.size = module->text_size + module->data_size;
266 hdr.type = SOF_FW_BASE; // module
267
268 count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
269 if (count != 1) {
270 fprintf(stderr, "error: failed to write section header %d\n",
271 -errno);
272 return -errno;
273 }
274
275 fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize");
276
277 fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n",
278 module->text_start, module->text_end,
279 module->text_end - module->text_start);
280 fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n",
281 module->data_start, module->data_end,
282 module->data_end - module->data_start);
283 fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ",
284 module->bss_start, module->bss_end,
285 module->bss_end - module->bss_start);
286
287 fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n");
288
289 err = write_block_reloc(image, module);
290 if (err < 0) {
Yan Wang3ad69eb2018-04-16 16:24:30 +0800291 fprintf(stderr, "error: failed to write section #%d\n", err);
Liam Girdwood7db25d82018-04-12 21:07:35 +0100292 return err;
293 }
294
295 fprintf(stdout, "\n");
296 return 0;
297}
298
Liam Girdwood05ef4342018-02-13 20:29:40 +0000299/* used by others */
300static int simple_write_firmware(struct image *image)
301{
302 struct snd_sof_fw_header hdr;
303 struct module *module;
304 size_t count;
305 int i, ret;
306
307 memcpy(hdr.sig, SND_SOF_FW_SIG, SND_SOF_FW_SIG_SIZE);
308
309 hdr.num_modules = image->num_modules;
310 hdr.abi = SND_SOF_FW_ABI;
311 hdr.file_size = 0;
312
313 for (i = 0; i < image->num_modules; i++) {
314 module = &image->module[i];
315 module->fw_size += sizeof(struct snd_sof_blk_hdr) *
316 (module->num_sections - module->num_bss);
317 module->fw_size += sizeof(struct snd_sof_mod_hdr) * hdr.num_modules;
318 hdr.file_size += module->fw_size;
319 }
320
321 count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
322 if (count != 1)
323 return -errno;
324
325 for (i = 0; i < image->num_modules; i++) {
326 module = &image->module[i];
327
328 fprintf(stdout, "writing module %d %s\n", i, module->elf_file);
329
Liam Girdwood7db25d82018-04-12 21:07:35 +0100330 if (image->reloc)
331 ret = simple_write_module_reloc(image, module);
332 else
333 ret = simple_write_module(image, module);
Liam Girdwood05ef4342018-02-13 20:29:40 +0000334 if (ret < 0) {
335 fprintf(stderr, "error: failed to write module %d\n",
336 i);
337 return ret;
338 }
339 }
340
341 fprintf(stdout, "firmware: image size %ld (0x%lx) bytes %d modules\n\n",
342 hdr.file_size + sizeof(hdr), hdr.file_size + sizeof(hdr),
343 hdr.num_modules);
344
345 return 0;
346}
347
348const struct adsp machine_byt = {
349 .name = "byt",
350 .iram_base = BYT_IRAM_BASE,
351 .iram_size = BYT_IRAM_SIZE,
352 .host_iram_offset = BYT_IRAM_HOST_OFFSET,
353 .dram_base = BYT_DRAM_BASE,
354 .dram_size = BYT_DRAM_SIZE,
355 .host_dram_offset = BYT_DRAM_HOST_OFFSET,
356 .machine_id = MACHINE_BAYTRAIL,
357 .write_firmware = simple_write_firmware,
358};
359
360const struct adsp machine_cht = {
361 .name = "cht",
362 .iram_base = BYT_IRAM_BASE,
363 .iram_size = BYT_IRAM_SIZE,
364 .host_iram_offset = BYT_IRAM_HOST_OFFSET,
365 .dram_base = BYT_DRAM_BASE,
366 .dram_size = BYT_DRAM_SIZE,
367 .host_dram_offset = BYT_DRAM_HOST_OFFSET,
368 .machine_id = MACHINE_CHERRYTRAIL,
369 .write_firmware = simple_write_firmware,
370};
371
372const struct adsp machine_bsw = {
373 .name = "bsw",
374 .iram_base = BYT_IRAM_BASE,
375 .iram_size = BYT_IRAM_SIZE,
376 .host_iram_offset = BYT_IRAM_HOST_OFFSET,
377 .dram_base = BYT_DRAM_BASE,
378 .dram_size = BYT_DRAM_SIZE,
379 .host_dram_offset = BYT_DRAM_HOST_OFFSET,
380 .machine_id = MACHINE_BRASWELL,
381 .write_firmware = simple_write_firmware,
382};
383
384const struct adsp machine_hsw = {
385 .name = "hsw",
386 .iram_base = HSW_IRAM_BASE,
387 .iram_size = HSW_IRAM_SIZE,
388 .host_iram_offset = HSW_IRAM_HOST_OFFSET,
389 .dram_base = HSW_DRAM_BASE,
390 .dram_size = HSW_DRAM_SIZE,
391 .host_dram_offset = HSW_DRAM_HOST_OFFSET,
392 .machine_id = MACHINE_HASWELL,
393 .write_firmware = simple_write_firmware,
394};
395
396const struct adsp machine_bdw = {
397 .name = "bdw",
398 .iram_base = BDW_IRAM_BASE,
399 .iram_size = BDW_IRAM_SIZE,
400 .host_iram_offset = BDW_IRAM_HOST_OFFSET,
401 .dram_base = BDW_DRAM_BASE,
402 .dram_size = BDW_DRAM_SIZE,
403 .host_dram_offset = BDW_DRAM_HOST_OFFSET,
404 .machine_id = MACHINE_BROADWELL,
405 .write_firmware = simple_write_firmware,
406};