rimage: Initial import of rimage firmware tool.

rimage converts ELF binaries to the firmware image file format understood
by the kernel audio drivers.

Signed-off-by: Liam Girdwood <liam.r.girdwood@linux.intel.com>
This commit is contained in:
Liam Girdwood 2016-09-27 17:29:55 +01:00
commit 04a535d508
14 changed files with 1485 additions and 0 deletions

18
.gitignore vendored Normal file
View File

@ -0,0 +1,18 @@
*.o
*.in
autom4te*
*.Po
*.swp
Makefile
config.*
configure
depcomp
install-sh
missing
stamp-h1
aclocal.m4
compile
ltmain.sh
rimage/rimage
rmbox/rmbox
rwav/rwav

1
Makefile.am Normal file
View File

@ -0,0 +1 @@
SUBDIRS = rimage rmbox

36
README Normal file
View File

@ -0,0 +1,36 @@
Sound Open Firmware Tools
=========================
This is a collection of open source tools used to develop open source audio
DSP firmwares for ALSA.
Building and Installing
=======================
./autogen.sh (only needed first time)
./configure
make
make install
rimage
======
rimage is used to convert ELF executable firmware files to the firmware file
formats used by the kernel drivers.
e.g.
rimage -i elf_file -o kernel_file -m machine
rimage can also convert kernel firmware formats to flat binaries formats to
assist in debugging :-
e.g. convert to flat binary, then ELF then dissasemble
rimage -i /lib/firmware/intel/reef-byt.ri -o image.bin -b -m byt
xtensa-byt-elf-objcopy -I binary -O elf32-xtensa-le -B xtensa image.bin image.bin.elf
xtensa-byt-elf-objdump -D image.bin.elf > image.dis.txt

6
autogen.sh Executable file
View File

@ -0,0 +1,6 @@
#!/bin/bash
libtoolize -c --force
aclocal -I m4 --install
autoconf -Wall
autoheader
automake -a --copy --foreign --add-missing

26
configure.ac Normal file
View File

@ -0,0 +1,26 @@
AC_PREREQ([2.69])
AC_INIT([rimage], [0.1])
AM_INIT_AUTOMAKE([foreign])
AC_CONFIG_SRCDIR([rimage/rimage.c])
AC_CONFIG_HEADERS([config.h])
AC_CANONICAL_HOST
dnl Initialize maintainer mode
AM_MAINTAINER_MODE([enable])
AC_PROG_CC
AC_OUTPUT([
Makefile
rimage/Makefile
rmbox/Makefile
])
echo "
prefix: ${prefix}
Compiler: ${CC}
CFLAGS: ${CFLAGS}
"

10
rimage/Makefile.am Normal file
View File

@ -0,0 +1,10 @@
bin_PROGRAMS = rimage
noinst_HEADERS = \
rimage.h
rimage_SOURCES = \
cherrytrail.c \
baytrail.c \
flat.c \
rimage.c

250
rimage/baytrail.c Normal file
View File

@ -0,0 +1,250 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "rimage.h"
#include "file_format.h"
/* taken from the linker scripts */
static const struct section byt_sections[] = {
{"ResetVector", 0xff2c0000, 0x2e0},
{"ResetVector.literal", 0xff2c02e0, 0x120},
{"WindowVectors", 0xff2c0400, 0x178},
{"Level2InterruptVector.literal", 0xff2c0578, 0x4},
{"Level2InterruptVector", 0xff2c057c, 0x1c},
{"Level3InterruptVector.literal", 0xff2c0598, 0x4},
{"Level3InterruptVector", 0xff2c059c, 0x1c},
{"Level4InterruptVector.literal", 0xff2c05b8, 0x4},
{"Level4InterruptVector", 0xff2c05bc, 0x1c},
{"Level5InterruptVector.literal", 0xff2c05d8, 0x4},
{"Level5InterruptVector", 0xff2c05dc, 0x1c},
{"DebugInterruptVector.literal", 0xff2c05d8, 0x4},
{"NMIExceptionVector", 0xff2c061c},
};
static const enum reef_module_id modules[] = {
REEF_MODULE_BASE_FW,
REEF_MODULE_AAC_5_1,
REEF_MODULE_PCM,
REEF_MODULE_PCM_SYSTEM,
REEF_MODULE_PCM_CAPTURE,
REEF_MODULE_PCM_REFERENCE,
REEF_MODULE_BLUETOOTH_RENDER_MODULE,
REEF_MODULE_BLUETOOTH_CAPTURE_MODULE,
};
static int is_iram(struct image *image, Elf32_Shdr *section)
{
const struct adsp *adsp = image->adsp;
uint32_t start, end;
start = section->sh_addr;
end = section->sh_addr + section->sh_size;
if (start < adsp->iram_base)
return 0;
if (start >= adsp->iram_base + adsp->iram_size)
return 0;
return 1;
}
static int is_dram(struct image *image, Elf32_Shdr *section)
{
const struct adsp *adsp = image->adsp;
uint32_t start, end;
start = section->sh_addr;
end = section->sh_addr + section->sh_size;
if (start < adsp->dram_base)
return 0;
if (start >= adsp->dram_base + adsp->dram_size)
return 0;
return 1;
}
static int block_idx = 0;
static int write_block(struct image *image, Elf32_Shdr *section)
{
const struct adsp *adsp = image->adsp;
struct dma_block_info block;
size_t count;
void *buffer;
int ret;
block.size = section->sh_size;
if (is_iram(image, section)) {
block.type = REEF_IRAM;
block.ram_offset = section->sh_addr - adsp->iram_base;
} else if (is_dram(image, section)) {
block.type = REEF_DRAM;
block.ram_offset = section->sh_addr - adsp->dram_base;
} else {
fprintf(stderr, "error: invalid block address/size 0x%x/0x%x\n",
section->sh_addr, section->sh_size);
return -EINVAL;
}
/* write header */
count = fwrite(&block, sizeof(block), 1, image->out_fd);
if (count != 1)
return -errno;
/* alloc data data */
buffer = calloc(1, section->sh_size);
if (buffer == NULL)
return -ENOMEM;
/* read in section data */
ret = fseek(image->in_fd, section->sh_offset, SEEK_SET);
if (ret < 0) {
fprintf(stderr, "error: cant seek to section %d\n", ret);
goto out;
}
count = fread(buffer, 1, section->sh_size, image->in_fd);
if (count != section->sh_size) {
fprintf(stderr, "error: cant read section %d\n", -errno);
ret = -errno;
goto out;
}
/* write out section data */
count = fwrite(buffer, 1, section->sh_size, image->out_fd);
if (count != section->sh_size) {
fprintf(stderr, "error: cant write section %d\n", -errno);
fprintf(stderr, " foffset %d size 0x%x mem addr 0x%x\n",
section->sh_offset, section->sh_size, section->sh_addr);
ret = -errno;
goto out;
}
if (image->verbose) {
fprintf(stdout, "block: %d\n foffset %d\n size 0x%x\n mem addr 0x%x\n",
block_idx++, section->sh_offset, section->sh_size,
section->sh_addr);
}
out:
free(buffer);
return ret;
}
/* used by others */
int byt_write_modules(struct image *image)
{
const struct adsp *adsp = image->adsp;
struct byt_module_header hdr;
Elf32_Shdr *section;
size_t count;
int i, err;
uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
memcpy(hdr.signature, REEF_FW_SIGN, REEF_FW_SIGNATURE_SIZE);
hdr.blocks = image->num_sections - image->num_bss;
hdr.mod_size = image->text_size + image->data_size + \
sizeof(struct dma_block_info) * hdr.blocks;
hdr.type = REEF_MODULE_BASE_FW;
hdr.entry_point = 0;//section->sh_addr;
count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
if (count != 1) {
fprintf(stderr, "error: failed to write section header %d\n", i);
return -errno ;
}
for (i = 0; i < image->hdr.e_shnum; i++) {
section = &image->section[i];
/* only write valid sections */
if (!(image->section[i].sh_flags & valid))
continue;
/* dont write bss */
if (section->sh_type == SHT_NOBITS)
continue;
err = write_block(image, section);
if (err < 0) {
fprintf(stderr, "error: failed to write section #%d\n", i);
return err;
}
}
/* write the remaining 7 fake modules headers, to make the linux driver happy */
hdr.mod_size = 0;
hdr.blocks = 0;
for (i = 1; i < sizeof(modules) / sizeof(modules[0]); i++) {
hdr.type = modules[i];
count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
if (count != 1) {
fprintf(stderr, "error: failed to write section header %d\n", i);
return -errno ;
}
}
return 0;
}
/* used by others */
int byt_write_header(struct image *image)
{
struct fw_header hdr;
size_t count;
memcpy(hdr.signature, REEF_FW_SIGN, REEF_FW_SIGNATURE_SIZE);
hdr.modules = sizeof(modules) / sizeof(modules[0]);
hdr.file_format = 0;
image->fw_size += sizeof(struct dma_block_info) *
(image->num_sections - image->num_bss);
image->fw_size += sizeof(struct byt_module_header) * hdr.modules;
hdr.file_size = image->fw_size;
fprintf(stdout, "fw: image size %ld (0x%lx) bytes %d modules\n\n",
hdr.file_size + sizeof(hdr), hdr.file_size + sizeof(hdr),
hdr.modules);
count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd);
if (count != 1)
return -errno;
return 0;
}
const struct adsp byt_machine = {
.name = "byt",
.iram_base = 0xff2c0000,
.iram_size = 0x14000,
.dram_base = 0xff300000,
.dram_size = 0x28000,
.image_size = 0xff300000 - 0xff2c0000 + 0x28000,
.dram_offset = 0xff300000 - 0xff2c0000,
.machine_id = MACHINE_BAYTRAIL,
.ops = {
.write_header = byt_write_header,
.write_modules = byt_write_modules,
},
.sections = byt_sections,
};

58
rimage/cherrytrail.c Normal file
View File

@ -0,0 +1,58 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "rimage.h"
#include "file_format.h"
/* TODO: need to config CHT values */
static const struct section cht_sections[] = {
{"ResetVector", 0xff2c0000, 0x2e0},
{"ResetVector.literal", 0xff2c02e0, 0x120},
{"WindowVectors", 0xff2c0400, 0x178},
{"Level2InterruptVector.literal", 0xff2c0578, 0x4},
{"Level2InterruptVector", 0xff2c057c, 0x1c},
{"Level3InterruptVector.literal", 0xff2c0598, 0x4},
{"Level3InterruptVector", 0xff2c059c, 0x1c},
{"Level4InterruptVector.literal", 0xff2c05b8, 0x4},
{"Level4InterruptVector", 0xff2c05bc, 0x1c},
{"Level5InterruptVector.literal", 0xff2c05d8, 0x4},
{"Level5InterruptVector", 0xff2c05dc, 0x1c},
{"DebugInterruptVector.literal", 0xff2c05d8, 0x4},
{"NMIExceptionVector", 0xff2c061c},
};
const struct adsp cht_machine = {
.name = "cht",
.iram_base = 0xff2c0000,
.iram_size = 0x14000,
.dram_base = 0xff300000,
.dram_size = 0x28000,
.image_size = 0xff300000 - 0xff2c0000 + 0x28000,
.dram_offset = 0xff300000 - 0xff2c0000,
.machine_id = MACHINE_CHERRYTRAIL,
.ops = {
.write_header = byt_write_header,
.write_modules = byt_write_modules,
},
.sections = cht_sections,
};

88
rimage/file_format.h Normal file
View File

@ -0,0 +1,88 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifndef __FILE_FORMAT_H__
#define __FILE_FORMAT_H__
#define REEF_FW_SIGNATURE_SIZE 4
#define REEF_FW_SIGN "$SST"
#define REEF_FW_LIB_SIGN "$LIB"
#define REEF_IRAM 1
#define REEF_DRAM 2
#define REEF_REGS 3
#define REEF_CACHE 3
enum reef_module_id {
REEF_MODULE_BASE_FW = 0x0,
REEF_MODULE_MP3 = 0x1,
REEF_MODULE_AAC_5_1 = 0x2,
REEF_MODULE_AAC_2_0 = 0x3,
REEF_MODULE_SRC = 0x4,
REEF_MODULE_WAVES = 0x5,
REEF_MODULE_DOLBY = 0x6,
REEF_MODULE_BOOST = 0x7,
REEF_MODULE_LPAL = 0x8,
REEF_MODULE_DTS = 0x9,
REEF_MODULE_PCM_CAPTURE = 0xA,
REEF_MODULE_PCM_SYSTEM = 0xB,
REEF_MODULE_PCM_REFERENCE = 0xC,
REEF_MODULE_PCM = 0xD,
REEF_MODULE_BLUETOOTH_RENDER_MODULE = 0xE,
REEF_MODULE_BLUETOOTH_CAPTURE_MODULE = 0xF,
REEF_MAX_MODULE_ID,
};
struct dma_block_info {
uint32_t type; /* IRAM/DRAM */
uint32_t size; /* Bytes */
uint32_t ram_offset; /* Offset in I/DRAM */
uint32_t rsvd; /* Reserved field */
} __attribute__((packed));
struct fw_module_info {
uint32_t persistent_size;
uint32_t scratch_size;
} __attribute__((packed));
struct fw_header {
unsigned char signature[REEF_FW_SIGNATURE_SIZE]; /* FW signature */
uint32_t file_size; /* size of fw minus this header */
uint32_t modules; /* # of modules */
uint32_t file_format; /* version of header format */
uint32_t reserved[4];
} __attribute__((packed));
/* ABI 0 - used by reef driver and CoE BDW/HSW firmware*/
struct hsw_module_header {
unsigned char signature[REEF_FW_SIGNATURE_SIZE]; /* module signature */
uint32_t mod_size; /* size of module */
uint32_t blocks; /* # of blocks */
uint16_t padding;
uint16_t type; /* codec type, pp lib */
uint32_t entry_point;
struct fw_module_info info;
} __attribute__((packed));
/* ABI 1 - used by CoE/MCG BYT/CHT/BSW driver */
struct byt_module_header {
unsigned char signature[REEF_FW_SIGNATURE_SIZE];
uint32_t mod_size; /* size of module */
uint32_t blocks; /* # of blocks */
uint32_t type; /* codec type, pp lib */
uint32_t entry_point;
}__attribute__((packed));
#endif

256
rimage/flat.c Normal file
View File

@ -0,0 +1,256 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "rimage.h"
#include "file_format.h"
static int dump_section(struct image *image, struct dma_block_info *block,
void *data)
{
const struct adsp *adsp = image->adsp;
uint32_t addr;
switch (block->type) {
case REEF_IRAM:
addr = block->ram_offset + adsp->iram_base;
break;
case REEF_DRAM:
addr = block->ram_offset + adsp->dram_base;
break;
case REEF_CACHE:
addr = block->ram_offset + adsp->dram_base;
break;
default:
return -EINVAL;
}
}
static int read_byt_bin_module(struct image *image,
struct byt_module_header *module)
{
const struct adsp *adsp = image->adsp;
struct dma_block_info *block;
int count, offset;
void *data;
block = (void *)module + sizeof(*module);
for (count = 0; count < module->blocks; count++) {
if (block->size <= 0) {
fprintf(stderr, "block %d size invalid\n", count);
return -EINVAL;
}
switch (block->type) {
case REEF_IRAM:
offset = block->ram_offset + 0;
break;
case REEF_DRAM:
offset = block->ram_offset +
adsp->dram_offset;
break;
case REEF_CACHE:
offset = block->ram_offset +
adsp->dram_offset;
break;
default:
fprintf(stderr, "wrong ram type 0x%x in block0x%x\n",
block->type, count);
return -EINVAL;
}
fprintf(stdout, "bin: block %d type %d offset 0x%x size 0x%x\n",
count, block->type, offset, block->size);
data = (void *)block + sizeof(*block);
memcpy(image->out_buffer + offset, data, block->size);
if (image->dump_sections)
dump_section(image, block, data);
block = (void *)block + sizeof(*block) + block->size;
}
return 0;
}
static int read_bdw_bin_module(struct image *image,
struct hsw_module_header *module)
{
const struct adsp *adsp = image->adsp;
struct dma_block_info *block;
int count, offset;
void *data;
block = (void *)module + sizeof(*module);
for (count = 0; count < module->blocks; count++) {
if (block->size <= 0) {
fprintf(stderr, "block %d size invalid\n", count);
return -EINVAL;
}
switch (block->type) {
case REEF_IRAM:
offset = block->ram_offset + 0;
break;
case REEF_DRAM:
offset = block->ram_offset +
adsp->dram_offset;
break;
case REEF_CACHE:
offset = block->ram_offset +
adsp->dram_offset;
break;
default:
fprintf(stderr, "wrong ram type 0x%x in block0x%x\n",
block->type, count);
return -EINVAL;
}
fprintf(stdout, "bin: block %d type %d offset 0x%x size 0x%x\n",
count, block->type, offset, block->size);
data = (void *)block + sizeof(*block);
memcpy(image->out_buffer + offset, data, block->size);
if (image->dump_sections)
dump_section(image, block, data);
block = (void *)block + sizeof(*block) + block->size;
}
return 0;
}
static int read_bin_data(struct image *image)
{
const struct adsp *adsp = image->adsp;
struct fw_header hdr;
size_t count;
count = fread(&hdr, sizeof(hdr), 1, image->in_fd);
if (count != 1)
return -errno;
if (strncmp(hdr.signature, REEF_FW_SIGN, REEF_FW_SIGNATURE_SIZE)) {
fprintf(stderr, "invalid header signature: %c%c%c%c\n",
hdr.signature[0], hdr.signature[1],
hdr.signature[2], hdr.signature[3]);
return -EINVAL;
}
image->fw_size = hdr.file_size;
image->num_modules = hdr.modules;
fprintf(stdout, "bin: input image size %ld (0x%lx) bytes %d modules\n",
hdr.file_size + sizeof(hdr), hdr.file_size + sizeof(hdr),
hdr.modules);
fprintf(stdout, "bin: output image size %d (0x%x) bytes\n",
adsp->image_size,
adsp->image_size);
image->in_buffer = calloc(image->fw_size, 1);
if (image->in_buffer == NULL)
return -ENOMEM;
count = fread(image->in_buffer, image->fw_size, 1, image->in_fd);
if (count != 1) {
free(image->in_buffer);
return -errno;
}
image->out_buffer = calloc(adsp->image_size, 1);
if (image->out_buffer == NULL) {
free(image->in_buffer);
return -ENOMEM;
}
return 0;
}
int write_byt_binary_image(struct image *image)
{
const struct adsp *adsp = image->adsp;
struct byt_module_header *module;
int ret, count;
ret = read_bin_data(image);
if (ret < 0)
return ret;
module = (void *)image->in_buffer;
for (count = 0; count < image->num_modules; count++) {
fprintf(stdout, "bin: module %d type %d blocks %d size 0x%x\n",
count, module->type, module->blocks, module->mod_size);
ret = read_byt_bin_module(image, module);
if (ret < 0) {
fprintf(stderr, "invalid module %d\n", count);
return ret;
}
module = (void *)module + sizeof(*module) + module->mod_size;
}
count = fwrite(image->out_buffer, adsp->image_size, 1,
image->out_fd);
if (count != adsp->image_size)
return -errno;
return ret;
}
int write_bdw_binary_image(struct image *image)
{
const struct adsp *adsp = image->adsp;
struct hsw_module_header *module;
int ret, count;
ret = read_bin_data(image);
if (ret < 0)
return ret;
module = (void *)image->in_buffer;
for (count = 0; count < image->num_modules; count++) {
fprintf(stdout, "bin: module %d type %d blocks %d size 0x%x\n",
count, module->type, module->blocks, module->mod_size);
ret = read_bdw_bin_module(image, module);
if (ret < 0) {
fprintf(stderr, "invalid module %d\n", count);
return ret;
}
module = (void *)module + sizeof(*module) + module->mod_size;
}
count = fwrite(image->out_buffer, adsp->image_size, 1,
image->out_fd);
if (count != adsp->image_size)
return -errno;
return ret;
}

312
rimage/rimage.c Normal file
View File

@ -0,0 +1,312 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <errno.h>
#include <string.h>
#include "rimage.h"
#include "file_format.h"
static const struct adsp *machine[] = {
&byt_machine,
&cht_machine,
};
static int read_elf_sections(struct image *image)
{
size_t count;
int i, ret;
uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR);
/* read in section header */
ret = fseek(image->in_fd, image->hdr.e_shoff, SEEK_SET);
if (ret < 0) {
fprintf(stderr, "error: cant seek to section header %d\n", ret);
return ret;
}
image->section = calloc(sizeof(Elf32_Shdr), image->hdr.e_shnum);
if (image->section == NULL)
return -ENOMEM;
count = fread(image->section, sizeof(Elf32_Shdr),
image->hdr.e_shnum, image->in_fd);
if (count != image->hdr.e_shnum) {
fprintf(stderr, "error: failed to read section header %d\n",
-errno);
return -errno;
}
for (i = 0; i < image->hdr.e_shnum; i++) {
/* only write valid sections */
if (!(image->section[i].sh_flags & valid))
continue;
switch (image->section[i].sh_type) {
case SHT_NOBITS:
/* bss */
image->bss_size += image->section[i].sh_size;
image->num_bss++;
break;
case SHT_PROGBITS:
/* text or data */
image->fw_size += image->section[i].sh_size;
if (image->section[i].sh_flags & SHF_EXECINSTR)
image->text_size += image->section[i].sh_size;
else
image->data_size += image->section[i].sh_size;
break;
default:
continue;
}
image->num_sections++;
if (!image->verbose)
continue;
fprintf(stdout, "section-%d: \ttype\t 0x%8.8x\n", i,
image->section[i].sh_type);
fprintf(stdout, "section-%d: \tflags\t 0x%8.8x\n", i,
image->section[i].sh_flags);
fprintf(stdout, "section-%d: \taddr\t 0x%8.8x\n", i,
image->section[i].sh_addr);
fprintf(stdout, "section-%d: \toffset\t 0x%8.8x\n", i,
image->section[i].sh_offset);
fprintf(stdout, "section-%d: \tsize\t 0x%8.8x\n", i,
image->section[i].sh_size);
fprintf(stdout, "section-%d: \tlink\t 0x%8.8x\n", i,
image->section[i].sh_link);
fprintf(stdout, "section-%d: \tinfo\t 0x%8.8x\n\n", i,
image->section[i].sh_info);
}
return 0;
}
static int read_elf_programs(struct image *image)
{
size_t count;
int i, ret;
/* read in program header */
ret = fseek(image->in_fd, image->hdr.e_phoff, SEEK_SET);
if (ret < 0) {
fprintf(stderr, "error: cant seek to program header %d\n", ret);
return ret;
}
image->prg = calloc(sizeof(Elf32_Phdr), image->hdr.e_phnum);
if (image->prg == NULL)
return -ENOMEM;
count = fread(image->prg, sizeof(Elf32_Phdr),
image->hdr.e_phnum, image->in_fd);
if (count != image->hdr.e_phnum) {
fprintf(stderr, "error: failed to read program header %d\n",
-errno);
return -errno;
}
for (i = 0; i < image->hdr.e_phnum; i++) {
if (image->prg[i].p_filesz == 0)
continue;
if (!image->verbose)
continue;
fprintf(stdout, "program-%d: \ttype\t 0x%8.8x\n", i,
image->prg[i].p_type);
fprintf(stdout, "program-%d: \toffset\t 0x%8.8x\n", i,
image->prg[i].p_offset);
fprintf(stdout, "program-%d: \tvaddr\t 0x%8.8x\n", i,
image->prg[i].p_vaddr);
fprintf(stdout, "program-%d: \tpaddr\t 0x%8.8x\n", i,
image->prg[i].p_paddr);
fprintf(stdout, "program-%d: \tfsize\t 0x%8.8x\n", i,
image->prg[i].p_filesz);
fprintf(stdout, "program-%d: \tmsize\t 0x%8.8x\n", i,
image->prg[i].p_memsz);
fprintf(stdout, "program-%d: \tflags\t 0x%8.8x\n\n", i,
image->prg[i].p_flags);
}
return 0;
}
static int write_elf_data(struct image *image)
{
const struct adsp *adsp = image->adsp;
int ret = 0;
size_t count;
/* read in elf header */
count = fread(&image->hdr, sizeof(image->hdr), 1, image->in_fd);
if (count != 1) {
fprintf(stderr, "error: failed to read elf header %d\n",
-errno);
return -errno;
}
fprintf(stdout, "elf: \tentry point\t 0x%8.8x\n", image->hdr.e_entry);
fprintf(stdout, "elf: \tprogram offset\t 0x%8.8x\n", image->hdr.e_phoff);
fprintf(stdout, "elf: \tsection offset\t 0x%8.8x\n", image->hdr.e_shoff);
fprintf(stdout, "elf: \tprogram size\t 0x%8.8x\n", image->hdr.e_phentsize);
fprintf(stdout, "elf: \tprogram count\t 0x%8.8x\n", image->hdr.e_phnum);
fprintf(stdout, "elf: \tsection size\t 0x%8.8x\n", image->hdr.e_shentsize);
fprintf(stdout, "elf: \tsection count\t 0x%8.8x\n", image->hdr.e_shnum);
fprintf(stdout, "elf: \tstring index\t 0x%8.8x\n\n", image->hdr.e_shstrndx);
ret = read_elf_programs(image);
if (ret < 0) {
fprintf(stderr, "error: failed to read program sections %d\n", ret);
goto out;
}
ret = read_elf_sections(image);
if (ret < 0) {
fprintf(stderr, "error: failed to read sections %d\n", ret);
goto out;
}
fprintf(stdout, "fw: input size %d (0x%x) bytes %d sections\n",
image->fw_size, image->fw_size, image->num_sections);
fprintf(stdout, "fw: text %d (0x%x) bytes\n"
" data %d (0x%x) bytes\n"
" bss %d (0x%x) bytes\n",
image->text_size, image->text_size,
image->data_size, image->data_size,
image->bss_size, image->bss_size);
ret = adsp->ops.write_header(image);
if (ret < 0) {
fprintf(stderr, "error: failed to write header %d\n", ret);
goto out;
}
ret = adsp->ops.write_modules(image);
if (ret < 0) {
fprintf(stderr, "error: failed to write modules %d\n", ret);
goto out;
}
out:
return ret;
}
static void usage(char *name)
{
fprintf(stdout, "%s:\t -m machine -i infile -o outfile\n", name);
fprintf(stdout, "\t -v enable verbose output\n");
exit(0);
}
int main(int argc, char *argv[])
{
struct image image;
const char *mach = NULL;
int opt, ret, i, binary = 0;
memset(&image, 0, sizeof(image));
while ((opt = getopt(argc, argv, "ho:i:m:vba:sk:")) != -1) {
switch (opt) {
case 'o':
image.out_file = optarg;
break;
case 'i':
image.in_file = optarg;
break;
case 'm':
mach = optarg;
break;
case 'v':
image.verbose = 1;
break;
case 'b':
binary = 1;
break;
case 's':
image.dump_sections = 1;
break;
case 'a':
image.abi = atoi(optarg);
break;
case 'h':
default: /* '?' */
usage(argv[0]);
}
}
if (image.in_file == NULL || image.out_file == NULL || mach == NULL)
usage(argv[0]);
/* find machine */
for (i = 0; i < ARRAY_SIZE(machine); i++) {
if (!strcmp(mach, machine[i]->name)) {
image.adsp = machine[i];
goto found;
}
}
fprintf(stderr, "error: machine %s not found\n", mach);
fprintf(stderr, "error: available machines ");
for (i = 0; i < ARRAY_SIZE(machine); i++)
fprintf(stderr, "%s, ", machine[i]->name);
fprintf(stderr, "/n");
return -EINVAL;
found:
/* open infile for reading */
image.in_fd = fopen(image.in_file, "r");
if (image.in_fd == NULL) {
fprintf(stderr, "error: unable to open %s for reading %d\n",
image.in_file, errno);
}
/* open outfile for reading */
image.out_fd = fopen(image.out_file, "w");
if (image.out_fd == NULL) {
fprintf(stderr, "error: unable to open %s for writing %d\n",
image.out_file, errno);
}
if (binary) {
switch(image.adsp->machine_id) {
case MACHINE_BAYTRAIL:
ret = write_byt_binary_image(&image);
break;
default:
fprintf(stderr, "error: not supported machine for binary input!\n");
return ret;
}
} else
ret = write_elf_data(&image);
/* close files */
fclose(image.out_fd);
fclose(image.in_fd);
return ret;
}

105
rimage/rimage.h Normal file
View File

@ -0,0 +1,105 @@
/*
* ELF to firmware image creator.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#ifndef __RIMAGE_H__
#define __RIMAGE_H__
#include <stdint.h>
#include <elf.h>
#include <stdio.h>
#include <openssl/conf.h>
#include <openssl/evp.h>
#include <openssl/err.h>
#define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0]))
struct adsp;
struct fw_image_manifest;
struct image {
const char *in_file;
const char *out_file;
FILE *in_fd;
FILE *out_fd;
void *pos;
Elf32_Ehdr hdr;
Elf32_Shdr *section;
Elf32_Phdr *prg;
const struct adsp *adsp;
int abi;
int verbose;
int num_sections;
int num_bss;
int fw_size;
int bss_size;
int text_size;
int data_size;
int file_size;
int num_modules;
/* disa */
void *in_buffer;
void *out_buffer;
int dump_sections;
};
struct section {
const char *name;
uint32_t addr;
uint32_t size;
};
struct adsp_ops {
/* write header or manifest */
int (*write_header)(struct image *image);
/* write data modules */
int (*write_modules)(struct image *image);
};
enum machine_id {
MACHINE_BAYTRAIL = 0,
MACHINE_CHERRYTRAIL,
MACHINE_MAX
};
struct adsp {
const char *name;
uint32_t iram_base;
uint32_t iram_size;
uint32_t dram_base;
uint32_t dram_size;
uint32_t image_size;
uint32_t dram_offset;
enum machine_id machine_id;
struct adsp_ops ops;
const struct section *sections;
};
/* headers used by multiple platforms */
int byt_write_header(struct image *image);
/* modules used by multiple platforms */
int byt_write_modules(struct image *image);
/* for disassembly */
int write_byt_binary_image(struct image *image);
/* supported machines */
extern const struct adsp byt_machine;
extern const struct adsp cht_machine;
#endif

4
rmbox/Makefile.am Normal file
View File

@ -0,0 +1,4 @@
bin_PROGRAMS = rmbox
rmbox_SOURCES = \
rmbox.c

315
rmbox/rmbox.c Normal file
View File

@ -0,0 +1,315 @@
/*
* mbox dump to debug log convertor.
*
* Copyright (c) 2015, Intel Corporation.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
* version 2, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*/
#include <stdlib.h>
#include <stdio.h>
#include <unistd.h>
#include <stdint.h>
#include <errno.h>
#include <string.h>
// TODO: include all this stuff
#define TRACE_CLASS_IRQ (1 << 24)
#define TRACE_CLASS_IPC (2 << 24)
#define TRACE_CLASS_PIPE (3 << 24)
#define TRACE_CLASS_HOST (4 << 24)
#define TRACE_CLASS_DAI (5 << 24)
#define TRACE_CLASS_DMA (6 << 24)
#define TRACE_CLASS_SSP (7 << 24)
#define TRACE_CLASS_COMP (8 << 24)
#define TRACE_CLASS_WAIT (9 << 24)
#define TRACE_CLASS_LOCK (10 << 24)
#define TRACE_CLASS_MEM (11 << 24)
#define TRACE_CLASS_MIXER (12 << 24)
#define MAILBOX_HOST_OFFSET 0x144000
#define MAILBOX_OUTBOX_OFFSET 0x0
#define MAILBOX_OUTBOX_SIZE 0x400
#define MAILBOX_OUTBOX_BASE \
(MAILBOX_BASE + MAILBOX_OUTBOX_OFFSET)
#define MAILBOX_INBOX_OFFSET MAILBOX_OUTBOX_SIZE
#define MAILBOX_INBOX_SIZE 0x400
#define MAILBOX_INBOX_BASE \
(MAILBOX_BASE + MAILBOX_INBOX_OFFSET)
#define MAILBOX_EXCEPTION_OFFSET \
(MAILBOX_INBOX_SIZE + MAILBOX_OUTBOX_SIZE)
#define MAILBOX_EXCEPTION_SIZE 0x100
#define MAILBOX_EXCEPTION_BASE \
(MAILBOX_BASE + MAILBOX_EXCEPTION_OFFSET)
#define MAILBOX_DEBUG_OFFSET \
(MAILBOX_EXCEPTION_SIZE + MAILBOX_EXCEPTION_OFFSET)
#define MAILBOX_DEBUG_SIZE 0x100
#define MAILBOX_DEBUG_BASE \
(MAILBOX_BASE + MAILBOX_DEBUG_OFFSET)
#define MAILBOX_STREAM_OFFSET \
(MAILBOX_DEBUG_SIZE + MAILBOX_DEBUG_OFFSET)
#define MAILBOX_STREAM_SIZE 0x200
#define MAILBOX_STREAM_BASE \
(MAILBOX_BASE + MAILBOX_STREAM_OFFSET)
#define MAILBOX_TRACE_OFFSET \
(MAILBOX_STREAM_SIZE + MAILBOX_STREAM_OFFSET)
#define MAILBOX_TRACE_SIZE 0x380
#define MAILBOX_TRACE_BASE \
(MAILBOX_BASE + MAILBOX_TRACE_OFFSET)
#define ARRAY_SIZE(x) (sizeof(x)/sizeof(x[0]))
static inline char get_char(uint32_t val, int idx)
{
char c = (val >> (idx * 8)) & 0xff;
if (c < '0' || c > 'z')
return '.';
else
return c;
}
static void usage(char *name)
{
fprintf(stdout, "%s:\t -i infile -o outfile\n", name);
exit(0);
}
static inline float to_usecs(uint32_t time)
{
/* trace timestamp uses CPU system clock at default 25MHz ticks */
// TODO: support variable clock rates
return (float)time / 25.0;
}
static void show_trace(uint32_t val, uint32_t addr, uint32_t *timestamp)
{
const char *trace;
uint32_t class;
/* timestamp or value ? */
if ((addr % 8) == 0) {
printf("trace.io: timestamp 0x%8.8x (%2.2f us) \tdelta 0x%8.8x (%2.2f us)\t",
(uint32_t)val, to_usecs(val),
(uint32_t)val - *timestamp, to_usecs(val - *timestamp));
*timestamp = val;
return;
}
class = val & 0xff000000;
if (class == TRACE_CLASS_IRQ)
trace = "irq";
else if (class == TRACE_CLASS_IPC)
trace = "ipc";
else if (class == TRACE_CLASS_PIPE)
trace = "pipe";
else if (class == TRACE_CLASS_HOST)
trace = "host";
else if (class == TRACE_CLASS_DAI)
trace = "dai";
else if (class == TRACE_CLASS_DMA)
trace = "dma";
else if (class == TRACE_CLASS_SSP)
trace = "ssp";
else if (class == TRACE_CLASS_COMP)
trace = "comp";
else if (class == TRACE_CLASS_WAIT)
trace = "wait";
else if (class == TRACE_CLASS_LOCK)
trace = "lock";
else if (class == TRACE_CLASS_MEM)
trace = "mem";
else if (class == TRACE_CLASS_MIXER)
trace = "mixer";
else {
printf("value 0x%8.8x\n", (uint32_t)val);
return;
}
printf("%s %c%c%c\n", trace,
(char)(val >> 16), (char)(val >> 8), (char)val);
}
static void show_debug(uint32_t val, uint32_t addr)
{
printf("debug: 0x%x (%2.2d) = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
(unsigned int)addr - MAILBOX_DEBUG_OFFSET,
((unsigned int)addr - MAILBOX_DEBUG_OFFSET) / 4,
val, val,
get_char(val, 3), get_char(val, 2),
get_char(val, 1), get_char(val, 0));
}
static void show_exception(uint32_t val, uint32_t addr)
{
printf("exp: 0x%x (%2.2d) = \t0x%8.8x \t(%8.8d) \t|%c%c%c%c|\n",
(unsigned int)addr - MAILBOX_EXCEPTION_OFFSET,
((unsigned int)addr - MAILBOX_EXCEPTION_OFFSET) / 4,
val, val,
get_char(val, 3), get_char(val, 2),
get_char(val, 1), get_char(val, 0));
}
struct sst_debugfs_map {
const char *name;
uint32_t size;
};
static const struct sst_debugfs_map debugfs_byt[] = {
{"dmac0", 0x420},
{"dmac1", 0x420},
{"ssp0", 0x100},
{"ssp1", 0x100},
{"ssp2", 0x100},
{"iram", 80 * 1024},
{"dram", 160 * 1024},
{"shim", 0x100},
{"mbox", 0x1000},
};
static int snapshot(const char *name)
{
const char *path = "/sys/kernel/debug";
uint32_t val, addr;
char pinname[64], poutname[64], buffer[128];
FILE *in_fd, *out_fd;
int i, count;
if (name == NULL)
return -EINVAL;
for (i = 0; i < ARRAY_SIZE(debugfs_byt); i++) {
sprintf(pinname, "%s/%s", path, debugfs_byt[i].name);
sprintf(poutname, "%s.%s.txt", name, debugfs_byt[i].name);
/* open debugfs for reading */
in_fd = fopen(pinname, "r");
if (in_fd == NULL) {
fprintf(stderr, "error: unable to open %s for reading %d\n",
pinname, errno);
continue;
}
/* open outfile for reading */
out_fd = fopen(poutname, "w");
if (out_fd == NULL) {
fprintf(stderr, "error: unable to open %s for writing %d\n",
poutname, errno);
fclose(in_fd);
continue;
}
fprintf(stdout, "processing %s...\n", pinname);
addr = 0;
while (1) {
count = fread(&val, 1, 4, in_fd);
if (count != 4)
break;
sprintf(buffer, "0x%6.6x: 0x%8.8x\n", addr, val);
count = fwrite(buffer, 1, strlen(buffer), out_fd);
addr += 4;
}
}
return 0;
}
int main(int argc, char *argv[])
{
int opt, count;
const char * out_file = NULL, *in_file = "/sys/kernel/debug/mbox";
FILE *in_fd, *out_fd;
char c, tmp[4] = {0};
uint32_t addr = 0, val, timestamp = 0;
while ((opt = getopt(argc, argv, "ho:i:s:")) != -1) {
switch (opt) {
case 'o':
out_file = optarg;
break;
case 'i':
in_file = optarg;
break;
case 's':
return snapshot(optarg);
case 'h':
default: /* '?' */
usage(argv[0]);
}
}
if (in_file == NULL || out_file == NULL)
usage(argv[0]);
/* open infile for reading */
in_fd = fopen(in_file, "r");
if (in_fd == NULL) {
fprintf(stderr, "error: unable to open %s for reading %d\n",
in_file, errno);
}
/* open outfile for reading */
out_fd = fopen(out_file, "w");
if (out_fd == NULL) {
fprintf(stderr, "error: unable to open %s for writing %d\n",
out_file, errno);
}
/* start to converting */
fprintf(stdout, "start to converting...\n");
while (1) {
count = fread(&tmp[0], 1, 4, in_fd);
if (count != 4)
break;
val = *((uint32_t*)tmp);
c = tmp[0];
tmp[0] = tmp[3];
tmp[3] = c;
c = tmp[1];
tmp[1] = tmp[2];
tmp[2] = c;
if (addr >= MAILBOX_TRACE_OFFSET &&
addr < MAILBOX_TRACE_OFFSET + MAILBOX_TRACE_SIZE)
show_trace(val, addr, &timestamp);
else if (addr >= MAILBOX_DEBUG_OFFSET &&
addr < MAILBOX_DEBUG_OFFSET + MAILBOX_DEBUG_SIZE)
show_debug(val, addr);
else if (addr >= MAILBOX_EXCEPTION_OFFSET &&
addr < MAILBOX_EXCEPTION_OFFSET + MAILBOX_EXCEPTION_SIZE)
show_exception(val, addr);
count = fwrite(&tmp[0], 1, 4, out_fd);
if (count != 4)
break;
addr += 4;
}
/* close files */
fclose(in_fd);
fclose(out_fd);
fprintf(stdout, "converting finished.\n");
}