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:
commit
04a535d508
|
@ -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
|
|
@ -0,0 +1 @@
|
|||
SUBDIRS = rimage rmbox
|
|
@ -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
|
||||
|
|
@ -0,0 +1,6 @@
|
|||
#!/bin/bash
|
||||
libtoolize -c --force
|
||||
aclocal -I m4 --install
|
||||
autoconf -Wall
|
||||
autoheader
|
||||
automake -a --copy --foreign --add-missing
|
|
@ -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}
|
||||
"
|
|
@ -0,0 +1,10 @@
|
|||
bin_PROGRAMS = rimage
|
||||
|
||||
noinst_HEADERS = \
|
||||
rimage.h
|
||||
|
||||
rimage_SOURCES = \
|
||||
cherrytrail.c \
|
||||
baytrail.c \
|
||||
flat.c \
|
||||
rimage.c
|
|
@ -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,
|
||||
};
|
|
@ -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,
|
||||
};
|
||||
|
|
@ -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
|
|
@ -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;
|
||||
}
|
|
@ -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;
|
||||
}
|
||||
|
|
@ -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
|
|
@ -0,0 +1,4 @@
|
|||
bin_PROGRAMS = rmbox
|
||||
|
||||
rmbox_SOURCES = \
|
||||
rmbox.c
|
|
@ -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, ×tamp);
|
||||
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");
|
||||
}
|
Loading…
Reference in New Issue