diff --git a/.gitignore b/.gitignore index 4c5b67bcba10..a3e8c17ffc71 100644 --- a/.gitignore +++ b/.gitignore @@ -20,6 +20,11 @@ *.dis *.lst .* +*.rm +*.met +*.uns +*.ro +*.debug Makefile Makefile.in diff --git a/configure.ac b/configure.ac index 6bd1323ca6dc..277a47f32139 100644 --- a/configure.ac +++ b/configure.ac @@ -364,6 +364,8 @@ AC_CONFIG_FILES([ src/library/include/Makefile src/library/include/platform/Makefile src/lib/Makefile + src/modules/Makefile + src/modules/template/Makefile src/platform/Makefile src/platform/baytrail/Makefile src/platform/baytrail/include/Makefile @@ -385,6 +387,8 @@ AC_CONFIG_FILES([ src/platform/cannonlake/include/platform/Makefile src/platform/cannonlake/include/xtensa/Makefile src/platform/cannonlake/include/xtensa/config/Makefile + src/test/Makefile + src/test/linker/Makefile ]) AC_OUTPUT diff --git a/rimage/elf.c b/rimage/elf.c index b1a1861b7a87..341e5a64ba01 100644 --- a/rimage/elf.c +++ b/rimage/elf.c @@ -283,6 +283,42 @@ static void elf_module_size(struct image *image, struct module *module, } } +static void elf_module_size_reloc(struct image *image, struct module *module, + Elf32_Shdr *section, int index) +{ + switch (section->sh_type) { + case SHT_PROGBITS: + /* text or data */ + if (section->sh_flags & SHF_EXECINSTR) { + /* text */ + module->text_start = 0; + module->text_end += section->sh_size; + + fprintf(stdout, "\tTEXT\t"); + } else { + /* initialized data, also calc the writable sections */ + module->data_start = 0; + module->data_end += section->sh_size; + + fprintf(stdout, "\tDATA\t"); + } + break; + case SHT_NOBITS: + /* bss */ + if (index == module->bss_index) { + /* updated the .bss segment */ + module->bss_start = section->sh_addr; + module->bss_end = section->sh_addr + section->sh_size; + fprintf(stdout, "\tBSS\t"); + } else { + fprintf(stdout, "\tHEAP\t"); + } + break; + default: + break; + } +} + static void elf_module_limits(struct image *image, struct module *module) { Elf32_Shdr *section; @@ -302,22 +338,29 @@ static void elf_module_limits(struct image *image, struct module *module) section = &module->section[i]; - /* only check valid sections */ - if (!(section->sh_flags & valid)) - continue; + /* module bss can sometimes be missed */ + if (i != module->bss_index) { - if (section->sh_size == 0) - continue; + /* only check valid sections */ + if (!(section->sh_flags & valid)) + continue; - if (elf_is_rom(image, section)) - continue; + if (section->sh_size == 0) + continue; + + if (elf_is_rom(image, section)) + continue; + } fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t%d", i, section->sh_addr, section->sh_addr + section->sh_size, section->sh_size); /* text or data section */ - elf_module_size(image, module, section, i); + if (image->reloc) + elf_module_size_reloc(image, module, section, i); + else + elf_module_size(image, module, section, i); /* section name */ fprintf(stdout, "%s\n", module->strings + section->sh_name); @@ -388,6 +431,10 @@ int elf_validate_modules(struct image *image) uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); int i, j, ret; + /* relocatable modules have no physical addresses until runtime */ + if (image->reloc) + return 0; + /* for each module */ for (i = 0; i < image->num_modules; i++) { module = &image->module[i]; @@ -484,6 +531,15 @@ int elf_parse_module(struct image *image, int module_index, const char *name) } module->elf_file = name; + /* get file size */ + ret = fseek(module->fd, 0, SEEK_END); + if (ret < 0) + goto hdr_err; + module->file_size = ftell(module->fd); + ret = fseek(module->fd, 0, SEEK_SET); + if (ret < 0) + goto hdr_err; + /* read in elf header */ ret = elf_read_hdr(image, module); if (ret < 0) diff --git a/rimage/file_simple.c b/rimage/file_simple.c index dcf0d5b241b4..893ac45b66f9 100644 --- a/rimage/file_simple.c +++ b/rimage/file_simple.c @@ -204,6 +204,98 @@ static int simple_write_module(struct image *image, struct module *module) return 0; } +static int write_block_reloc(struct image *image, struct module *module) +{ + struct snd_sof_blk_hdr block; + size_t count; + void *buffer; + int ret; + + block.size = module->file_size; + block.type = SOF_BLK_DATA; + block.offset = 0; + + /* write header */ + count = fwrite(&block, sizeof(block), 1, image->out_fd); + if (count != 1) + return -errno; + + /* alloc data data */ + buffer = calloc(1, module->file_size); + if (buffer == NULL) + return -ENOMEM; + + /* read in section data */ + ret = fseek(module->fd, 0, SEEK_SET); + if (ret < 0) { + fprintf(stderr, "error: can't seek to section %d\n", ret); + goto out; + } + count = fread(buffer, 1, module->file_size, module->fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't read section %d\n", -errno); + ret = -errno; + goto out; + } + + /* write out section data */ + count = fwrite(buffer, 1, module->file_size, image->out_fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't write section %d\n", -errno); + ret = -errno; + goto out; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%8.8lx\t%s\n", block_idx++, + 0, module->file_size, ftell(image->out_fd), + block.type == SOF_BLK_TEXT ? "TEXT" : "DATA"); + +out: + free(buffer); + return ret; +} + +static int simple_write_module_reloc(struct image *image, struct module *module) +{ + struct snd_sof_mod_hdr hdr; + size_t count; + int i, err; + + hdr.num_blocks = 1; + hdr.size = module->text_size + module->data_size; + hdr.type = SOF_FW_BASE; // module + + count = fwrite(&hdr, sizeof(hdr), 1, image->out_fd); + if (count != 1) { + fprintf(stderr, "error: failed to write section header %d\n", + -errno); + return -errno; + } + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\t\tType\n"); + + err = write_block_reloc(image, module); + if (err < 0) { + fprintf(stderr, "error: failed to write section #%d\n", i); + return err; + } + + fprintf(stdout, "\n"); + return 0; +} + /* used by others */ static int simple_write_firmware(struct image *image) { @@ -235,7 +327,10 @@ static int simple_write_firmware(struct image *image) fprintf(stdout, "writing module %d %s\n", i, module->elf_file); - ret = simple_write_module(image, module); + if (image->reloc) + ret = simple_write_module_reloc(image, module); + else + ret = simple_write_module(image, module); if (ret < 0) { fprintf(stderr, "error: failed to write module %d\n", i); diff --git a/rimage/manifest.c b/rimage/manifest.c index 87f80d7c8719..d88d39b80434 100644 --- a/rimage/manifest.c +++ b/rimage/manifest.c @@ -403,7 +403,6 @@ static int man_module_create(struct image *image, struct module *module, fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); - /* validate segments */ if (man_module_validate(man_module) < 0) return -EINVAL; @@ -445,6 +444,98 @@ static int man_module_create(struct image *image, struct module *module, return 0; } +static int man_module_create_reloc(struct image *image, struct module *module, + struct sof_man_module *man_module) +{ + /* create module and segments */ + int err; + unsigned int pages; + void *buffer = image->fw_image + module->foffset; + size_t count; + + image->image_end = 0; + + err = man_get_module_manifest(image, module, man_module); + if (err < 0) + return err; + + /* stack size ??? convert sizes to PAGES */ + man_module->instance_bss_size = 1; + + /* max number of instances of this module ?? */ + man_module->instance_max_count = 1; + + fprintf(stdout, "\n\tTotals\tStart\t\tEnd\t\tSize"); + + fprintf(stdout, "\n\tTEXT\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->text_start, module->text_end, + module->text_end - module->text_start); + fprintf(stdout, "\tDATA\t0x%8.8x\t0x%8.8x\t0x%x\n", + module->data_start, module->data_end, + module->data_end - module->data_start); + fprintf(stdout, "\tBSS\t0x%8.8x\t0x%8.8x\t0x%x\n\n ", + module->bss_start, module->bss_end, + module->bss_end - module->bss_start); + + /* main module */ + /* text section is first */ + man_module->segment[SOF_MAN_SEGMENT_TEXT].file_offset = + module->foffset; + man_module->segment[SOF_MAN_SEGMENT_TEXT].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length = 0; + + /* data section */ + man_module->segment[SOF_MAN_SEGMENT_RODATA].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_RODATA].file_offset = + module->foffset; + pages = module->data_file_size / MAN_PAGE_SIZE; + if (module->data_file_size % MAN_PAGE_SIZE) + pages += 1; + + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length = pages; + + /* bss is last */ + man_module->segment[SOF_MAN_SEGMENT_BSS].file_offset = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].v_base_addr = 0; + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length = 0; + + fprintf(stdout, "\tNo\tAddress\t\tSize\t\tFile\tType\n"); + + /* seek to beginning of file */ + err = fseek(module->fd, 0, SEEK_SET); + if (err < 0) { + fprintf(stderr, "error: can't seek to section %d\n", err); + return err; + } + + count = fread(buffer, 1, module->file_size, module->fd); + if (count != module->file_size) { + fprintf(stderr, "error: can't read section %d\n", -errno); + return -errno; + } + + fprintf(stdout, "\t%d\t0x%8.8x\t0x%8.8x\t0x%x\t%s\n", 0, + 0, module->file_size, 0, "DATA"); + + + fprintf(stdout, "\n"); + image->image_end = module->foffset + module->file_size; + + /* round module end up to nearest page */ + if (image->image_end % MAN_PAGE_SIZE) { + image->image_end = (image->image_end / MAN_PAGE_SIZE) + 1; + image->image_end *= MAN_PAGE_SIZE; + } + + fprintf(stdout, " Total pages text %d data %d bss %d module file limit: 0x%x\n\n", + man_module->segment[SOF_MAN_SEGMENT_TEXT].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_RODATA].flags.r.length, + man_module->segment[SOF_MAN_SEGMENT_BSS].flags.r.length, + image->image_end); + return 0; +} + + static int man_write_unsigned_mod(struct image *image) { int count; @@ -555,7 +646,11 @@ static int man_write_fw(struct image *image) module->foffset = image->image_end; } - ret = man_module_create(image, module, man_module); + if (image->reloc) + ret = man_module_create_reloc(image, module, + man_module); + else + ret = man_module_create(image, module, man_module); if (ret < 0) goto err; } diff --git a/rimage/rimage.c b/rimage/rimage.c index 322820b02612..cc0a6101c44d 100644 --- a/rimage/rimage.c +++ b/rimage/rimage.c @@ -35,8 +35,10 @@ static const struct adsp *machine[] = { static void usage(char *name) { - fprintf(stdout, "%s:\t -m machine -o outfile -k [key] ELF files\n", name); + fprintf(stdout, "%s:\t -m machine -o outfile -k [key] ELF files\n", + name); fprintf(stdout, "\t -v enable verbose output\n"); + fprintf(stdout, "\t -r enable relocatable ELF files\n"); exit(0); } @@ -48,7 +50,7 @@ int main(int argc, char *argv[]) memset(&image, 0, sizeof(image)); - while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:")) != -1) { + while ((opt = getopt(argc, argv, "ho:m:vba:sk:l:r")) != -1) { switch (opt) { case 'o': image.out_file = optarg; @@ -68,6 +70,9 @@ int main(int argc, char *argv[]) case 'k': image.key_name = optarg; break; + case 'r': + image.reloc = 1; + break; case 'h': usage(argv[0]); break; diff --git a/rimage/rimage.h b/rimage/rimage.h index 8b46766d4cdf..888e7e8e781a 100644 --- a/rimage/rimage.h +++ b/rimage/rimage.h @@ -78,6 +78,9 @@ struct module { int text_file_size; int text_fixup_size; int data_file_size; + + /* total file size */ + int file_size; }; /* @@ -92,6 +95,7 @@ struct image { const struct adsp *adsp; int abi; int verbose; + int reloc; /* ELF data is relocatable */ int num_modules; struct module module[MAX_MODULES]; uint32_t image_end;/* module end, equal to output image size */ diff --git a/src/Makefile.am b/src/Makefile.am index 331dd0d66dbc..b8d0768bd7ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,9 +4,9 @@ export COMMON_INCDIR = \ $(PLATFORM_INCDIR) if BUILD_LIB -SUBDIRS = ipc math audio arch include library +SUBDIRS = ipc math audio arch include library test endif if BUILD_XTENSA -SUBDIRS = include init math audio platform tasks drivers ipc lib arch +SUBDIRS = include init math audio platform tasks drivers ipc lib arch modules endif diff --git a/src/arch/host/include/arch/Makefile.am b/src/arch/host/include/arch/Makefile.am index bf2de6d2fcf2..726bba53edcd 100644 --- a/src/arch/host/include/arch/Makefile.am +++ b/src/arch/host/include/arch/Makefile.am @@ -1,9 +1,12 @@ includedir = $(prefix)/include/sof/arch include_HEADERS = \ + atomic.h \ cache.h \ interrupt.h \ + reloc.h \ sof.h \ spinlock.h \ + task.h \ timer.h \ wait.h diff --git a/src/arch/host/include/arch/atomic.h b/src/arch/host/include/arch/atomic.h new file mode 100644 index 000000000000..80c4522f8500 --- /dev/null +++ b/src/arch/host/include/arch/atomic.h @@ -0,0 +1,77 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + */ + +#ifndef __ARCH_ATOMIC_H_ +#define __ARCH_ATOMIC_H_ + +#include +#include + +typedef struct { + volatile int32_t value; +} atomic_t; + +static inline void arch_atomic_init(atomic_t *a, int32_t value) +{ + a->value = value; +} + +static inline void arch_atomic_add(atomic_t *a, int32_t value) +{ + int32_t result, current; + + __asm__ __volatile__( + "1: l32i %1, %2, 0\n" + " wsr %1, scompare1\n" + " add %0, %1, %3\n" + " s32c1i %0, %2, 0\n" + " bne %0, %1, 1b\n" + : "=&a" (result), "=&a" (current) + : "a" (&a->value), "a" (value) + : "memory"); +} + +static inline void arch_atomic_sub(atomic_t *a, int32_t value) +{ + int32_t result, current; + + __asm__ __volatile__( + "1: l32i %1, %2, 0\n" + " wsr %1, scompare1\n" + " sub %0, %1, %3\n" + " s32c1i %0, %2, 0\n" + " bne %0, %1, 1b\n" + : "=&a" (result), "=&a" (current) + : "a" (&a->value), "a" (value) + : "memory"); +} + +#endif diff --git a/src/arch/host/include/arch/reloc.h b/src/arch/host/include/arch/reloc.h new file mode 100644 index 000000000000..c5b9a4e25c82 --- /dev/null +++ b/src/arch/host/include/arch/reloc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + */ + +#ifndef __INCLUDE_ARCH_RELOC_SOF__ +#define __INCLUDE_ARCH_RELOC_SOF__ + +struct sof; +struct sof_module; + +int arch_reloc_init(struct sof *sof); +int arch_elf_reloc_sections(struct sof_module *smod); +int arch_elf_parse_sections(struct sof_module *smod); + +#endif diff --git a/src/arch/host/include/arch/task.h b/src/arch/host/include/arch/task.h new file mode 100644 index 000000000000..2ec5f25ef196 --- /dev/null +++ b/src/arch/host/include/arch/task.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2017, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + */ + +#ifndef __ARCH_TASK_H_ +#define __ARCH_TASK_H_ + +struct task; + +void arch_run_task(struct task *task); + +void arch_allocate_tasks(void); + +int arch_assign_tasks(void); + +#endif diff --git a/src/arch/xtensa/Makefile.am b/src/arch/xtensa/Makefile.am index 9f53e88731b4..47e6eccbc85b 100644 --- a/src/arch/xtensa/Makefile.am +++ b/src/arch/xtensa/Makefile.am @@ -33,7 +33,8 @@ sof_SOURCES = \ _vectors.S \ init.c \ timer.c \ - task.c + task.c \ + reloc.c if BUILD_CANNONLAKE sof_SOURCES += \ diff --git a/src/arch/xtensa/include/arch/Makefile.am b/src/arch/xtensa/include/arch/Makefile.am index 8e08ff591655..335d87c19de2 100644 --- a/src/arch/xtensa/include/arch/Makefile.am +++ b/src/arch/xtensa/include/arch/Makefile.am @@ -2,6 +2,7 @@ noinst_HEADERS = \ atomic.h \ cache.h \ interrupt.h \ + reloc.h \ sof.h \ spinlock.h \ task.h \ diff --git a/src/arch/xtensa/include/arch/reloc.h b/src/arch/xtensa/include/arch/reloc.h new file mode 100644 index 000000000000..c5b9a4e25c82 --- /dev/null +++ b/src/arch/xtensa/include/arch/reloc.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + */ + +#ifndef __INCLUDE_ARCH_RELOC_SOF__ +#define __INCLUDE_ARCH_RELOC_SOF__ + +struct sof; +struct sof_module; + +int arch_reloc_init(struct sof *sof); +int arch_elf_reloc_sections(struct sof_module *smod); +int arch_elf_parse_sections(struct sof_module *smod); + +#endif diff --git a/src/arch/xtensa/reloc.c b/src/arch/xtensa/reloc.c new file mode 100644 index 000000000000..2a9766290bb4 --- /dev/null +++ b/src/arch/xtensa/reloc.c @@ -0,0 +1,426 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#include +#include +#include + +#define trace_module(__e) trace_event_atomic(TRACE_CLASS_MODULE, __e) +#define trace_module_value(__e) trace_value_atomic(__e) +#define trace_module_error(__e) trace_error(TRACE_CLASS_MODULE, __e) + +#define XCC_MOD_OFFSET 0x8 + +#define XTENSA_OPCODE_CALLN 0x5 +#define XTENSA_OPMASK_CALLN 0xf + +#define XTENSA_OPCODE_L32R 0x1 +#define XTENSA_OPMASK_L32R 0xf + +struct section { + struct elf32_section_hdr *shdr; + void *data; +}; + +struct rela { + struct elf32_section_hdr *shdr; + struct elf32_relocation *item; +}; + +struct reloc { + + /* header */ + struct elf32_file_hdr *hdr; + void *elf; + + /* section headers */ + struct elf32_section_hdr *sect_hdr; + + /* strings */ + struct elf32_section_hdr *str_section; + void *str_buf; + + /* symbols */ + struct elf32_section_hdr *sym_section; + struct elf32_symbol *symbol; + + struct section section[3]; + struct rela rela[3]; + + struct sof_symbol *symbols; + int num_symbols; +}; + +static struct reloc *reloc; + +static inline const char *elf_get_string(struct reloc *reloc, int offset) +{ + return (const char *)(reloc->str_buf + offset); +} + +static inline uint32_t elf_get_symbol_addr(struct reloc *reloc, + const char *symbol) +{ + int i; + + /* search symbol table for symbol */ + for (i = 0; i < reloc->num_symbols; i++) { + + if (!rstrcmp(symbol, reloc->symbols[i].name)) + return reloc->symbols[i].value; + } + + return 0; +} + +static int elf_reloc_section(struct reloc *reloc, + struct elf32_relocation *item, + struct elf32_symbol *symbol, + void *section_base) +{ + unsigned char *rloc; + uint32_t rval; + const char *symbol_name; + + /* reloc location */ + rloc = reloc->elf + reloc->sect_hdr[symbol->st_shndx].sh_offset + + item->r_offset; + + /* calc value depending on type */ + switch (ELF32_ST_BIND(symbol->st_info)) { + case STB_GLOBAL: + + /* get symbol name */ + symbol_name = elf_get_string(reloc, symbol->st_name); + if (!symbol_name) + return -EINVAL; + + /* get symbol address */ + rval = elf_get_symbol_addr(reloc, symbol_name); + if (rval == 0) + return -EINVAL; + + rval += item->r_addend; + break; + case STB_LOCAL: + case STB_WEAK: + default: + rval = (uint32_t)section_base + item->r_addend; + break; + } + + /* relocate based on reloc type */ + switch (ELF32_R_TYPE(item->r_info)) { + case R_XTENSA_NONE: + case R_XTENSA_ASM_EXPAND: + case R_XTENSA_DIFF8: + case R_XTENSA_DIFF16: + case R_XTENSA_DIFF32: + /* nothing to do for these relocs */ + break; + case R_XTENSA_32: + case R_XTENSA_PLT: + /* add value to location as 32 bit value */ + *(uint32_t *)rloc += rval; + break; + + case R_XTENSA_SLOT0_OP: + /* both these calls are PC relative - do we need to reloc ? */ + if ((rloc[0] & XTENSA_OPMASK_CALLN) == XTENSA_OPCODE_CALLN) { + + trace_value(0xca11); + + } else if ((rloc[0] & XTENSA_OPMASK_L32R) == + XTENSA_OPCODE_L32R) { + + trace_value(0x1325); + } + break; + + default: + /* cant reloc this type */ + return -EINVAL; + } + + return 0; +} + +static int elf_reloc_sections(struct reloc *reloc, struct section *section, + struct rela *rela, void *section_base) +{ + struct elf32_symbol *sym; + int i; + int num_relocs; + int err; + + /* make sure section and relocation tables exist */ + if (section == NULL || section->shdr == NULL) + return 0; + if (rela == NULL || rela->shdr == NULL) + return 0; + + num_relocs = section->shdr->sh_size / sizeof(struct elf32_relocation); + + /* for each relocation */ + for (i = 0; i < num_relocs; i++) { + + /* get symbol table entry for relocation */ + sym = &reloc->symbol[ELF32_R_SYM(rela->item[i].r_info)]; + + err = elf_reloc_section(reloc, &rela->item[i], sym, + section_base); + if (err < 0) + return err; + } + + return 0; +} + +static inline void reloc_new_section(struct reloc *reloc, int type, + struct elf32_section_hdr *hdr) +{ + reloc->section[type].shdr = hdr; + reloc->section[type].data = reloc->elf + hdr->sh_offset; +} + +/* find our sof_module_drv in the ELF data */ +static inline void reloc_driver(struct sof_module *smod, struct reloc *reloc, + struct elf32_section_hdr *hdr) +{ + smod->drv = reloc->elf + hdr->sh_offset; + + /* try offset at offset 0 */ + if (!rstrcmp(smod->drv->magic, MODULE_MAGIC)) + return; + + /* xcc places driver at offset */ + smod->drv = reloc->elf + hdr->sh_offset + XCC_MOD_OFFSET; + if (!rstrcmp(smod->drv->magic, MODULE_MAGIC)) + return; + + /* not found */ + trace_module_error("ed0"); + smod->drv = NULL; +} + +/* get data for text and data sections */ +static inline void reloc_parse_progs(struct sof_module *smod, + struct reloc *reloc, + struct elf32_section_hdr *hdr, + const char *name) +{ + if (hdr->sh_flags & SHF_EXECINSTR) { + /* text sections */ + if (!rstrcmp(".text", name)) { + reloc_new_section(reloc, SOF_TEXT_SECTION, hdr); + smod->text_bytes = hdr->sh_size; + } + } else { + /* data sections */ + if (!rstrcmp(".data", name)) { + reloc_new_section(reloc, SOF_DATA_SECTION, hdr); + smod->data_bytes = hdr->sh_size; + } else if (!rstrcmp(".rodata", name)) { + reloc_new_section(reloc, SOF_RODATA_SECTION, hdr); + smod->rodata_bytes = hdr->sh_size; + } else if (!rstrcmp(".module.drv", name)) { + reloc_driver(smod, reloc, hdr); + } + } +} + +static inline void reloc_new_rela(struct reloc *reloc, int type, + struct elf32_section_hdr *hdr) +{ + reloc->rela[type].shdr = hdr; + reloc->rela[type].item = reloc->elf + hdr->sh_offset; +} + +/* get data for relocation sections */ +static inline void reloc_parse_relas(struct reloc *reloc, + struct elf32_section_hdr *hdr, const char *name) +{ + if (!rstrcmp(".rela.data", name)) + reloc_new_rela(reloc, SOF_DATA_SECTION, hdr); + + if (!rstrcmp(".rela.rodata", name)) + reloc_new_rela(reloc, SOF_RODATA_SECTION, hdr); + + if (!rstrcmp(".rela.text", name)) + reloc_new_rela(reloc, SOF_TEXT_SECTION, hdr); +} + +int arch_elf_parse_sections(struct sof_module *smod) +{ + struct elf32_section_hdr *sect_hdr; + struct elf32_file_hdr *hdr; + int i; + uint32_t valid = (SHF_WRITE | SHF_ALLOC | SHF_EXECINSTR); + const char *sect_name; + + /* ELF header */ + reloc->hdr = smod->elf; + hdr = reloc->hdr; + + /* section header */ + reloc->sect_hdr = reloc->elf + hdr->e_shoff; + sect_hdr = reloc->sect_hdr; + + /* string header */ + reloc->str_section = §_hdr[hdr->e_shstrndx]; + + /* parse each section for needed data */ + for (i = 0; i < hdr->e_shnum; i++) { + + /* is section empty ? */ + if (sect_hdr[i].sh_size == 0) + continue; + + /* get the section name */ + sect_name = (char *)reloc->elf + + reloc->str_section->sh_offset + sect_hdr[i].sh_name; + + switch (sect_hdr[i].sh_type) { + case SHT_NOBITS: + /* bss */ + smod->bss_bytes = sect_hdr[i].sh_size; + break; + case SHT_PROGBITS: + /* text or data */ + + /* only relocate valid sections */ + if (!(sect_hdr[i].sh_flags & valid)) + continue; + + reloc_parse_progs(smod, reloc, §_hdr[i], sect_name); + break; + case SHT_RELA: + reloc_parse_relas(reloc, §_hdr[i], sect_name); + break; + case SHT_SYMTAB: + if (!rstrcmp(".symtab", sect_name)) { + reloc->sym_section = §_hdr[i]; + reloc->symbol = + reloc->elf + sect_hdr[i].sh_offset; + } + break; + case SHT_STRTAB: + if (!rstrcmp(".strtab", sect_name)) { + reloc->str_section = §_hdr[i]; + reloc->str_buf = + reloc->elf + sect_hdr[i].sh_offset; + } + break; + default: + continue; + } + } + + /* validate ELF file - check for text section */ + if (!smod->text_bytes) { + trace_module_error("ep0"); + return -EINVAL; + } + /* check for strings */ + if (!reloc->str_buf) { + trace_module_error("ep1"); + return -EINVAL; + } + /* check for symbols */ + if (!reloc->sym_section) { + trace_module_error("ep2"); + return -EINVAL; + } + /* check for relocation tables */ + if (!reloc->rela[SOF_TEXT_SECTION].shdr) { + trace_module_error("ep3"); + return -EINVAL; + } + /* check for module driver */ + if (!smod->drv) { + trace_module_error("ep4"); + return -EINVAL; + } + + return 0; +} + +int arch_elf_reloc_sections(struct sof_module *smod) +{ + int ret; + + /* relocate each rela */ + ret = elf_reloc_sections(reloc, &reloc->section[SOF_TEXT_SECTION], + &reloc->rela[SOF_TEXT_SECTION], smod->text); + if (ret < 0) + goto err; + + ret = elf_reloc_sections(reloc, &reloc->section[SOF_DATA_SECTION], + &reloc->rela[SOF_DATA_SECTION], smod->data); + if (ret < 0) + goto err; + + ret = elf_reloc_sections(reloc, &reloc->section[SOF_RODATA_SECTION], + &reloc->rela[SOF_RODATA_SECTION], smod->rodata); + if (ret < 0) + goto err; + + /* write and invalidate text section */ + rmemcpy(smod->text, reloc->section[SOF_TEXT_SECTION].data, + smod->text_bytes); + icache_invalidate_region(smod->text, smod->text_bytes); + + /* write and invalidate data sections */ + rmemcpy(smod->data, reloc->section[SOF_DATA_SECTION].data, + smod->data_bytes); + dcache_invalidate_region(smod->data, smod->data_bytes); + rmemcpy(smod->rodata, reloc->section[SOF_RODATA_SECTION].data, + smod->rodata_bytes); + dcache_invalidate_region(smod->rodata, smod->rodata_bytes); + + bzero(smod->bss, smod->bss_bytes); + dcache_invalidate_region(smod->bss, smod->bss_bytes); + return ret; + +err: + return ret; +} + +int arch_reloc_init(struct sof *sof) +{ + reloc = rzalloc(RZONE_SYS, SOF_MEM_CAPS_RAM, sizeof(*reloc)); + reloc->symbols = (struct sof_symbol *)_symbol_table_start; + reloc->num_symbols = (_symbol_table_end - _symbol_table_start) / + sizeof(struct sof_symbol); + sof->reloc = reloc; + + return 0; +} + diff --git a/src/include/sof/Makefile.am b/src/include/sof/Makefile.am index b66745927df5..5d118317e829 100644 --- a/src/include/sof/Makefile.am +++ b/src/include/sof/Makefile.am @@ -23,6 +23,7 @@ include_HEADERS = \ list.h \ lock.h \ mailbox.h \ + module.h \ notifier.h \ panic.h \ sof.h \ diff --git a/src/include/sof/intel-ipc.h b/src/include/sof/intel-ipc.h index f89e9b57910f..a59c106f152b 100644 --- a/src/include/sof/intel-ipc.h +++ b/src/include/sof/intel-ipc.h @@ -38,7 +38,6 @@ struct intel_ipc_data { /* DMA */ struct dma *dmac; uint8_t *page_table; - completion_t complete; /* PM */ int pm_prepare_D3; /* do we need to prepare for D3 */ diff --git a/src/include/sof/ipc.h b/src/include/sof/ipc.h index 2e1818df4d9d..06425b340b45 100644 --- a/src/include/sof/ipc.h +++ b/src/include/sof/ipc.h @@ -134,6 +134,14 @@ int ipc_send_short_msg(uint32_t msg); void ipc_platform_do_cmd(struct ipc *ipc); void ipc_platform_send_msg(struct ipc *ipc); +/* create a SG page table eme list from a compressed page table */ +int ipc_parse_page_descriptors(uint8_t *page_table, + struct sof_ipc_host_buffer *ring, + struct list_item *elem_list, + uint32_t direction); +int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, + struct sof_ipc_host_buffer *ring); + /* * IPC Component creation and destruction. */ diff --git a/src/include/sof/module.h b/src/include/sof/module.h new file mode 100644 index 000000000000..396b53fda337 --- /dev/null +++ b/src/include/sof/module.h @@ -0,0 +1,194 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#ifndef __INCLUDE_SOF_MODULE__ +#define __INCLUDE_SOF_MODULE__ + +#include +#include +#include +#include +#include + +#define MODULE_MAGIC "SOF_MOD" +#define MODULE_ABI {0, 0} + +/* ELF 32bit file header */ +struct elf32_file_hdr { + uint8_t e_ident[16]; + uint16_t e_type; + uint16_t e_machine; + uint32_t e_version; + uint32_t e_entry; + uint32_t e_phoff; + uint32_t e_shoff; + uint32_t e_flags; + uint16_t e_ehsize; + uint16_t e_phentsize; + uint16_t e_phnum; + uint16_t e_shentsize; + uint16_t e_shnum; + uint16_t e_shstrndx; +}; + +/* section types - sh_type */ +#define SHT_PROGBITS 1 +#define SHT_SYMTAB 2 +#define SHT_STRTAB 3 +#define SHT_RELA 4 +#define SHT_NOBITS 8 + +/* section flags - sh_flags */ +#define SHF_WRITE (1 << 0) +#define SHF_ALLOC (1 << 1) +#define SHF_EXECINSTR (1 << 2) + +/* ELF 32bit section header */ +struct elf32_section_hdr { + uint32_t sh_name; + uint32_t sh_type; + uint32_t sh_flags; + uint32_t sh_addr; + uint32_t sh_offset; + uint32_t sh_size; + uint32_t sh_link; + uint32_t sh_info; + uint32_t sh_addralign; + uint32_t sh_entsize; +}; + +/* relocation info data - r_info */ +#define ELF32_R_SYM(val) ((val) >> 8) +#define ELF32_R_TYPE(val) ((val) & 0xff) + +/* relocation types - r_info */ +#define R_XTENSA_NONE 0 +#define R_XTENSA_32 1 +#define R_XTENSA_PLT 6 +#define R_XTENSA_ASM_EXPAND 11 +#define R_XTENSA_32_PCREL 14 +#define R_XTENSA_DIFF8 17 +#define R_XTENSA_DIFF16 18 +#define R_XTENSA_DIFF32 19 +#define R_XTENSA_SLOT0_OP 20 + +/* ELF 32bit relocation entry */ +struct elf32_relocation { + uint32_t r_offset; + uint32_t r_info; + int32_t r_addend; +}; + +/* binding information - st_info */ +#define ELF32_ST_BIND(val) (((uint8_t) (val)) >> 4) +#define ELF32_ST_TYPE(val) ((val) & 0xf) + +/* binding types - st_info */ +#define STB_LOCAL 0 +#define STB_GLOBAL 1 +#define STB_WEAK 2 + +/* ELF 32bit symbol table entry */ +struct elf32_symbol { + uint32_t st_name; + uint32_t st_value; + uint32_t st_size; + uint8_t st_info; + uint8_t st_other; + uint16_t st_shndx; +}; + +/* + * ELF module data + */ + +#define SOF_DATA_SECTION 0 +#define SOF_RODATA_SECTION 1 +#define SOF_TEXT_SECTION 2 + +/* linker script sets both point to start and end of symbol table */ +extern unsigned long _symbol_table_start; +extern unsigned long _symbol_table_end; + +struct sof_module; + +/* module driver */ +struct sof_module_drv { + char magic[8]; /* to help loader */ + uint16_t abi[2]; /* to validate against basefw runtime */ + char isa[4]; /* ISA configuration */ + + /* general purpose entry and exit - mandatory */ + int (*init)(struct sof_module *mod); + int (*exit)(struct sof_module *mod); +}; + +struct sof_module { + /* driver */ + struct sof *sof; + struct sof_module_drv *drv; + void *private; /* not touched by core */ + + /* size of eacch section after parsing */ + size_t bss_bytes; + size_t text_bytes; + size_t data_bytes; + size_t rodata_bytes; + + /* pointer to buffers for each section */ + void *text; + void *data; + void *rodata; + void *bss; + + /* ELF data */ + struct elf32_file_hdr *elf; + + struct list_item list; +}; + +#define SOF_MODULE(name, minit, mexit) \ + const struct sof_module_drv _module_##name \ + __attribute__((used)) \ + __attribute__((section(".module.drv"), used)) \ + = { MODULE_MAGIC, MODULE_ABI, PLATFORM_ISA, minit, mexit, } + +#define SOF_MODULE_REF(name) \ + (uint32_t)( &_module_##name ) + +#define SOF_MODULE_DECL(name) \ + extern const struct sof_module_drv _module_##name + +struct sof_module *module_init(struct sof *sof, struct ipc_module_new *mod); +int module_reloc(struct sof *sof, struct sof_module *module); +int module_probe(struct sof *sof, struct sof_module *module); +int module_remove(struct sof *sof, struct sof_module *module); + +#endif diff --git a/src/include/sof/sof.h b/src/include/sof/sof.h index b9d7aff0419f..cb4d77dbf0fb 100644 --- a/src/include/sof/sof.h +++ b/src/include/sof/sof.h @@ -33,6 +33,7 @@ #include #include +#include #include struct ipc; @@ -44,6 +45,30 @@ struct sa; ({const typeof(((type *)0)->member) *__memberptr = (ptr); \ (type *)((char *)__memberptr - offsetof(type, member));}) +/* + * Firmware symbol table. + */ +struct sof_symbol { + unsigned long value; + const char *name; +}; + +#define SOF_SYMBOL_STRING(sym) \ + static const char _symbolstr_##sym[] \ + __attribute__((section("_symbol_strings"), aligned(1))) = #sym + +#define SOF_SYMBOL_ELEM(sym) \ + static const struct sof_symbol _symbol_elem_##sym \ + __attribute__((used)) \ + __attribute__((section("_symbol_table"), used)) \ + = { (unsigned long)&sym, _symbolstr_##sym } + +/* functions must be exported to be in the symbol table */ +#define EXPORT(sym) \ + extern typeof(sym) sym; \ + SOF_SYMBOL_STRING(sym); \ + SOF_SYMBOL_ELEM(sym); + /* general firmware context */ struct sof { /* init data */ @@ -58,6 +83,10 @@ struct sof { /* DMA for Trace*/ struct dma_trace_data *dmat; + + /* module relocator */ + struct reloc *reloc; + struct list_item module_list; /* list of modules */ }; #endif diff --git a/src/include/sof/trace.h b/src/include/sof/trace.h index 5409a1fae1f9..b3ddc6201450 100644 --- a/src/include/sof/trace.h +++ b/src/include/sof/trace.h @@ -95,6 +95,7 @@ #define TRACE_CLASS_EQ_FIR (19 << 24) #define TRACE_CLASS_EQ_IIR (20 << 24) #define TRACE_CLASS_SA (21 << 24) +#define TRACE_CLASS_MODULE (22 << 24) /* move to config.h */ #define TRACE 1 diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index fbf1c072865f..18b7aebfd96d 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -151,6 +151,7 @@ #define SOF_MEM_CAPS_HP (1 << 4) /* high performance */ #define SOF_MEM_CAPS_DMA (1 << 5) /* DMA'able */ #define SOF_MEM_CAPS_CACHE (1 << 6) /* cacheable */ +#define SOF_MEM_CAPS_EXEC (1 << 7) /* executable */ /* * Command Header - Header for all IPC. Identifies IPC message. @@ -727,6 +728,16 @@ struct sof_ipc_pipe_comp_connect { uint32_t sink_id; } __attribute__((packed)); + +/* + * Runtime Modules + */ +struct ipc_module_new { + struct sof_ipc_hdr hdr; + struct sof_ipc_host_buffer buffer; + uint32_t stream_tag; +} __attribute__((packed)); + /* * PM */ diff --git a/src/ipc/apl-ipc.c b/src/ipc/apl-ipc.c index 78291d03b74b..cc18c0f86a1c 100644 --- a/src/ipc/apl-ipc.c +++ b/src/ipc/apl-ipc.c @@ -173,6 +173,7 @@ void ipc_platform_send_msg(struct ipc *ipc) out: spin_unlock_irq(&ipc->lock, flags); } +EXPORT(ipc_platform_send_msg); int platform_ipc_init(struct ipc *ipc) { diff --git a/src/ipc/byt-ipc.c b/src/ipc/byt-ipc.c index 87e7949bd3ba..3a5e9204ea66 100644 --- a/src/ipc/byt-ipc.c +++ b/src/ipc/byt-ipc.c @@ -198,6 +198,7 @@ void ipc_platform_send_msg(struct ipc *ipc) out: spin_unlock_irq(&ipc->lock, flags); } +EXPORT(ipc_platform_send_msg); int platform_ipc_init(struct ipc *ipc) { diff --git a/src/ipc/cnl-ipc.c b/src/ipc/cnl-ipc.c index ba651643afdd..8d722fab7c4d 100644 --- a/src/ipc/cnl-ipc.c +++ b/src/ipc/cnl-ipc.c @@ -173,6 +173,7 @@ void ipc_platform_send_msg(struct ipc *ipc) out: spin_unlock_irq(&ipc->lock, flags); } +EXPORT(ipc_platform_send_msg); int platform_ipc_init(struct ipc *ipc) { diff --git a/src/ipc/dma-copy.c b/src/ipc/dma-copy.c index be72eb8c49a9..107193af9805 100644 --- a/src/ipc/dma-copy.c +++ b/src/ipc/dma-copy.c @@ -169,6 +169,7 @@ int dma_copy_to_host(struct dma_copy *dc, struct dma_sg_config *host_sg, /* bytes copied */ return bytes_copied; } +EXPORT(dma_copy_to_host); /* Copy DSP memory to host memory. * Copies DSP memory to host in a single PAGE_SIZE or smaller block. Does not @@ -189,6 +190,7 @@ int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, /* bytes copied */ return size; } +EXPORT(dma_copy_to_host_nowait); #else @@ -238,6 +240,7 @@ int dma_copy_to_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg, /* bytes copied */ return local_sg_elem.size; } +EXPORT(dma_copy_to_host_nowait); #endif @@ -322,6 +325,7 @@ int dma_copy_from_host(struct dma_copy *dc, struct dma_sg_config *host_sg, /* bytes copied */ return bytes_copied; } +EXPORT(dma_copy_from_host); /* Copy host memory to DSP memory. * Copies host memory to DSP in a single PAGE_SIZE or smaller block. Does not @@ -372,6 +376,7 @@ int dma_copy_from_host_nowait(struct dma_copy *dc, struct dma_sg_config *host_sg /* bytes copied */ return local_sg_elem.size; } +EXPORT(dma_copy_from_host_nowait); int dma_copy_new(struct dma_copy *dc, int dmac) { @@ -396,6 +401,7 @@ int dma_copy_new(struct dma_copy *dc, int dmac) return 0; } +EXPORT(dma_copy_new); #if defined CONFIG_DMA_GW diff --git a/src/ipc/handler.c b/src/ipc/handler.c index 6a51765b7faf..581ce9e75d2d 100644 --- a/src/ipc/handler.c +++ b/src/ipc/handler.c @@ -83,134 +83,6 @@ static inline struct sof_ipc_hdr *mailbox_validate(void) return hdr; } -#ifdef CONFIG_HOST_PTABLE -static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next) -{ - struct intel_ipc_data *iipc = (struct intel_ipc_data *)data; - - if (type == DMA_IRQ_TYPE_LLIST) - wait_completed(&iipc->complete); -} - -/* - * Copy the audio buffer page tables from the host to the DSP max of 4K. - */ -static int get_page_descriptors(struct intel_ipc_data *iipc, - struct sof_ipc_host_buffer *ring) -{ - struct dma_sg_config config; - struct dma_sg_elem elem; - struct dma *dma; - int chan; - int ret = 0; - - /* get DMA channel from DMAC */ - chan = dma_channel_get(iipc->dmac, 0); - if (chan < 0) { - trace_ipc_error("ePC"); - return chan; - } - dma = iipc->dmac; - - /* set up DMA configuration */ - config.direction = DMA_DIR_HMEM_TO_LMEM; - config.src_width = sizeof(uint32_t); - config.dest_width = sizeof(uint32_t); - config.cyclic = 0; - list_init(&config.elem_list); - - /* set up DMA descriptor */ - elem.dest = (uint32_t)iipc->page_table; - elem.src = ring->phy_addr; - - /* source buffer size is always PAGE_SIZE bytes */ - /* 20 bits for each page, round up to 32 */ - elem.size = (ring->pages * 5 * 16 + 31) / 32; - list_item_prepend(&elem.list, &config.elem_list); - - ret = dma_set_config(dma, chan, &config); - if (ret < 0) { - trace_ipc_error("ePs"); - goto out; - } - - /* set up callback */ - dma_set_cb(dma, chan, DMA_IRQ_TYPE_LLIST, dma_complete, iipc); - - wait_init(&iipc->complete); - - /* start the copy of page table to DSP */ - dma_start(dma, chan); - - /* wait for DMA to complete */ - iipc->complete.timeout = PLATFORM_HOST_DMA_TIMEOUT; - ret = wait_for_completion_timeout(&iipc->complete); - - /* compressed page tables now in buffer at _ipc->page_table */ -out: - dma_channel_put(dma, chan); - return ret; -} - -/* - * Parse the host page tables and create the audio DMA SG configuration - * for host audio DMA buffer. This involves creating a dma_sg_elem for each - * page table entry and adding each elem to a list in struct dma_sg_config. - */ -static int parse_page_descriptors(struct intel_ipc_data *iipc, - struct sof_ipc_host_buffer *ring, struct list_item *elem_list, - uint32_t direction) -{ - int i; - uint32_t idx; - uint32_t phy_addr; - struct dma_sg_elem *e; - - /* the ring size may be not multiple of the page size, the last - * page may be not full used. The used size should be in range - * of (ring->pages - 1, ring->pages] * PAGES. - */ - if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) || - (ring->size > HOST_PAGE_SIZE * ring->pages)) { - /* error buffer size */ - trace_ipc_error("eBs"); - return -EINVAL; - } - - for (i = 0; i < ring->pages; i++) { - idx = (((i << 2) + i)) >> 1; - phy_addr = iipc->page_table[idx] | (iipc->page_table[idx + 1] << 8) - | (iipc->page_table[idx + 2] << 16); - - if (i & 0x1) - phy_addr <<= 8; - else - phy_addr <<= 12; - phy_addr &= 0xfffff000; - - /* allocate new host DMA elem and add it to our list */ - e = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*e)); - if (!e) - return -ENOMEM; - - if (direction == SOF_IPC_STREAM_PLAYBACK) - e->src = phy_addr; - else - e->dest = phy_addr; - - /* the last page may be not full used */ - if (i == (ring->pages - 1)) - e->size = ring->size - HOST_PAGE_SIZE * i; - else - e->size = HOST_PAGE_SIZE; - - list_item_append(&e->list, elem_list); - } - - return 0; -} -#endif - /* * Stream IPC Operations. */ @@ -258,7 +130,8 @@ static int ipc_stream_pcm_params(uint32_t stream) list_init(&elem_list); /* use DMA to read in compressed page table ringbuffer from host */ - err = get_page_descriptors(iipc, &pcm_params->params.buffer); + err = ipc_get_page_descriptors(iipc->dmac, iipc->page_table, + &pcm_params->params.buffer); if (err < 0) { trace_ipc_error("eAp"); goto error; @@ -268,8 +141,9 @@ static int ipc_stream_pcm_params(uint32_t stream) host = (struct sof_ipc_comp_host *)&cd->comp; ring_size = pcm_params->params.buffer.size; - err = parse_page_descriptors(iipc, &pcm_params->params.buffer, - &elem_list, host->direction); + err = ipc_parse_page_descriptors(iipc->page_table, + &pcm_params->params.buffer, + &elem_list, host->direction); if (err < 0) { trace_ipc_error("eAP"); goto error; @@ -656,7 +530,8 @@ static int ipc_dma_trace_config(uint32_t header) list_init(&elem_list); /* use DMA to read in compressed page table ringbuffer from host */ - err = get_page_descriptors(iipc, ¶ms->buffer); + err = ipc_get_page_descriptors(iipc->dmac, iipc->page_table, + ¶ms->buffer); if (err < 0) { trace_ipc_error("eCp"); goto error; @@ -667,8 +542,8 @@ static int ipc_dma_trace_config(uint32_t header) /* Parse host tables */ ring_size = params->buffer.size; - err = parse_page_descriptors(iipc, ¶ms->buffer, - &elem_list, SOF_IPC_STREAM_CAPTURE); + err = ipc_parse_page_descriptors(iipc->page_table, ¶ms->buffer, + &elem_list, SOF_IPC_STREAM_CAPTURE); if (err < 0) { trace_ipc_error("ePP"); goto error; diff --git a/src/ipc/hsw-ipc.c b/src/ipc/hsw-ipc.c index aa4d9e145be0..7edd785a9bdc 100644 --- a/src/ipc/hsw-ipc.c +++ b/src/ipc/hsw-ipc.c @@ -194,6 +194,7 @@ void ipc_platform_send_msg(struct ipc *ipc) out: spin_unlock_irq(&ipc->lock, flags); } +EXPORT(ipc_platform_send_msg); int platform_ipc_init(struct ipc *ipc) { diff --git a/src/ipc/ipc.c b/src/ipc/ipc.c index ed2cbb8ebbc9..fbb1be6c3875 100644 --- a/src/ipc/ipc.c +++ b/src/ipc/ipc.c @@ -39,6 +39,7 @@ #include #include #include +#include #include #include #include @@ -366,6 +367,134 @@ int ipc_comp_dai_config(struct ipc *ipc, struct sof_ipc_dai_config *config) return ret; } +#ifdef CONFIG_HOST_PTABLE +/* + * Parse the host page tables and create the audio DMA SG configuration + * for host audio DMA buffer. This involves creating a dma_sg_elem for each + * page table entry and adding each elem to a list in struct dma_sg_config. + */ +int ipc_parse_page_descriptors(uint8_t *page_table, + struct sof_ipc_host_buffer *ring, + struct list_item *elem_list, + uint32_t direction) +{ + int i; + uint32_t idx; + uint32_t phy_addr; + struct dma_sg_elem *e; + + /* the ring size may be not multiple of the page size, the last + * page may be not full used. The used size should be in range + * of (ring->pages - 1, ring->pages] * PAGES. + */ + if ((ring->size <= HOST_PAGE_SIZE * (ring->pages - 1)) || + (ring->size > HOST_PAGE_SIZE * ring->pages)) { + /* error buffer size */ + trace_ipc_error("eBs"); + return -EINVAL; + } + + for (i = 0; i < ring->pages; i++) { + idx = (((i << 2) + i)) >> 1; + phy_addr = page_table[idx] | (page_table[idx + 1] << 8) + | (page_table[idx + 2] << 16); + + if (i & 0x1) + phy_addr <<= 8; + else + phy_addr <<= 12; + phy_addr &= 0xfffff000; + + /* allocate new host DMA elem and add it to our list */ + e = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*e)); + if (!e) + return -ENOMEM; + + if (direction == SOF_IPC_STREAM_PLAYBACK) + e->src = phy_addr; + else + e->dest = phy_addr; + + /* the last page may be not full used */ + if (i == (ring->pages - 1)) + e->size = ring->size - HOST_PAGE_SIZE * i; + else + e->size = HOST_PAGE_SIZE; + + list_item_append(&e->list, elem_list); + } + + return 0; +} + +static void dma_complete(void *data, uint32_t type, struct dma_sg_elem *next) +{ + completion_t *complete = data; + + if (type == DMA_IRQ_TYPE_LLIST) + wait_completed(complete); +} + +/* + * Copy the audio buffer page tables from the host to the DSP max of 4K. + */ +int ipc_get_page_descriptors(struct dma *dmac, uint8_t *page_table, + struct sof_ipc_host_buffer *ring) +{ + struct dma_sg_config config; + struct dma_sg_elem elem; + completion_t complete; + int chan; + int ret = 0; + + /* get DMA channel from DMAC */ + chan = dma_channel_get(dmac, 0); + if (chan < 0) { + trace_ipc_error("ePC"); + return chan; + } + + /* set up DMA configuration */ + config.direction = DMA_DIR_HMEM_TO_LMEM; + config.src_width = sizeof(uint32_t); + config.dest_width = sizeof(uint32_t); + config.cyclic = 0; + list_init(&config.elem_list); + + /* set up DMA descriptor */ + elem.dest = (uint32_t)page_table; + elem.src = ring->phy_addr; + + /* source buffer size is always PAGE_SIZE bytes */ + /* 20 bits for each page, round up to 32 */ + elem.size = (ring->pages * 5 * 16 + 31) / 32; + list_item_prepend(&elem.list, &config.elem_list); + + ret = dma_set_config(dmac, chan, &config); + if (ret < 0) { + trace_ipc_error("ePs"); + goto out; + } + + /* set up callback */ + dma_set_cb(dmac, chan, DMA_IRQ_TYPE_LLIST, dma_complete, &complete); + + wait_init(&complete); + + /* start the copy of page table to DSP */ + dma_start(dmac, chan); + + /* wait for DMA to complete */ + complete.timeout = PLATFORM_HOST_DMA_TIMEOUT; + ret = wait_for_completion_timeout(&complete); + + /* compressed page tables now in buffer at _ipc->page_table */ +out: + dma_channel_put(dmac, chan); + return ret; +} +#endif + int ipc_init(struct sof *sof) { int i; diff --git a/src/lib/Makefile.am b/src/lib/Makefile.am index 825bfbdb5a09..c891b97d2bc4 100644 --- a/src/lib/Makefile.am +++ b/src/lib/Makefile.am @@ -9,7 +9,8 @@ libcore_a_SOURCES = \ schedule.c \ agent.c \ interrupt.c \ - dma-trace.c + dma-trace.c \ + module.c libcore_a_CFLAGS = \ $(ARCH_CFLAGS) \ diff --git a/src/lib/agent.c b/src/lib/agent.c index b672f235563c..accdf7386ac2 100644 --- a/src/lib/agent.c +++ b/src/lib/agent.c @@ -57,6 +57,7 @@ void sa_enter_idle(struct sof *sof) sa->last_idle = platform_timer_get(platform_timer); } +EXPORT(sa_enter_idle); static uint64_t validate(void *data, uint64_t delay) { diff --git a/src/lib/alloc.c b/src/lib/alloc.c index 3ca14c3f93e2..4b6ae5f50454 100644 --- a/src/lib/alloc.c +++ b/src/lib/alloc.c @@ -405,6 +405,7 @@ void *rmalloc(int zone, uint32_t caps, size_t bytes) spin_unlock_irq(&memmap.lock, flags); return ptr; } +EXPORT(rmalloc); void *rzalloc(int zone, uint32_t caps, size_t bytes) { @@ -417,6 +418,7 @@ void *rzalloc(int zone, uint32_t caps, size_t bytes) return ptr; } +EXPORT(rzalloc); /* allocates continuous buffers */ void *rballoc(int zone, uint32_t caps, size_t bytes) @@ -471,6 +473,7 @@ void *rballoc(int zone, uint32_t caps, size_t bytes) spin_unlock_irq(&memmap.lock, flags); return ptr; } +EXPORT(rballoc); void rfree(void *ptr) { @@ -480,6 +483,7 @@ void rfree(void *ptr) free_block(ptr); spin_unlock_irq(&memmap.lock, flags); } +EXPORT(rfree); uint32_t mm_pm_context_size(void) { diff --git a/src/lib/interrupt.c b/src/lib/interrupt.c index e8e2899541d5..3b01c5f8bca5 100644 --- a/src/lib/interrupt.c +++ b/src/lib/interrupt.c @@ -167,6 +167,7 @@ int interrupt_register(uint32_t irq, else return irq_register_child(parent, irq, handler, arg); } +EXPORT(interrupt_register); void interrupt_unregister(uint32_t irq) { @@ -179,6 +180,7 @@ void interrupt_unregister(uint32_t irq) else irq_unregister_child(parent, irq); } +EXPORT(interrupt_unregister); uint32_t interrupt_enable(uint32_t irq) { @@ -191,6 +193,7 @@ uint32_t interrupt_enable(uint32_t irq) else return irq_enable_child(parent, irq); } +EXPORT(interrupt_enable); uint32_t interrupt_disable(uint32_t irq) { @@ -203,3 +206,4 @@ uint32_t interrupt_disable(uint32_t irq) else return irq_disable_child(parent, irq); } +EXPORT(interrupt_disable); diff --git a/src/lib/lib.c b/src/lib/lib.c index 79198fd95899..a2d258229013 100644 --- a/src/lib/lib.c +++ b/src/lib/lib.c @@ -65,6 +65,7 @@ void *memcpy(void *dest, const void *src, size_t n) arch_memcpy(dest, src, n); return dest; } +EXPORT(memcpy); /* generic bzero - TODO: can be optimsed for ARCH ? */ void bzero(void *s, size_t n) @@ -84,6 +85,7 @@ void bzero(void *s, size_t n) for (i = 0; i < r; i++) d8[i] = 0; } +EXPORT(bzero); /* generic memset - TODO: can be optimsed for ARCH ? */ void *memset(void *s, int c, size_t n) @@ -97,6 +99,7 @@ void *memset(void *s, int c, size_t n) return s; } +EXPORT(memset); /* generic strlen - TODO: can be optimsed for ARCH ? */ int rstrlen(const char *s) @@ -106,6 +109,7 @@ int rstrlen(const char *s) while(*p++ != 0); return (p - s) - 1; } +EXPORT(rstrlen); /* generic string compare */ int rstrcmp(const char *s1, const char *s2) @@ -122,4 +126,5 @@ int rstrcmp(const char *s1, const char *s2) /* match */ return 0; } +EXPORT(rstrcmp); diff --git a/src/lib/module.c b/src/lib/module.c new file mode 100644 index 000000000000..3f91a84c67a2 --- /dev/null +++ b/src/lib/module.c @@ -0,0 +1,253 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include +#include +#include +#include +#include + +#define trace_module(__e) trace_event_atomic(TRACE_CLASS_MODULE, __e) +#define trace_module_value(__e) trace_value_atomic(__e) +#define trace_module_error(__e) trace_error(TRACE_CLASS_MODULE, __e) + +#define PLATFORM_HOST_DMAC 0 + +/* size in 4k pages */ +#define MODULE_PAGE_TABLE_SIZE 32 + +static int copy_module(struct sof_module *smod, struct ipc_module_new *ipc_mod) +{ + struct dma_copy dc; + uint8_t *page_table; + struct dma_sg_config sg_config; +#ifdef CONFIG_HOST_PTABLE + struct list_item elem_list; +#endif + struct dma_sg_elem elem; + int ret; + + /* validate */ + if (ipc_mod->buffer.pages > MODULE_PAGE_TABLE_SIZE) { + trace_module_error("me0"); + return NULL; + } + + /* allocate page table */ + page_table = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, + MODULE_PAGE_TABLE_SIZE); + if (!page_table) { + trace_module_error("mc1"); + return NULL; + } + + /* allocate ELF data - freed as not needed after relocations */ + smod->elf = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, + ipc_mod->buffer.size); + if (!smod) { + trace_module_error("mc2"); + goto mod_buf_err; + } + + /* get DMAC for copy */ + ret = dma_copy_new(&dc, PLATFORM_HOST_DMAC); + if (ret < 0) { + trace_module_error("mc3"); + goto dma_cp_err; + } + +#ifdef CONFIG_HOST_PTABLE + + list_init(&elem_list); + + /* use DMA to read in compressed page table ringbuffer from host */ + ret = ipc_get_page_descriptors(dc.dmac, page_table, + &ipc_mod->buffer); + if (ret < 0) { + trace_ipc_error("mc4"); + goto dma_cp_err; + } + + ret = ipc_parse_page_descriptors(page_table, &ipc_mod->buffer, + &elem_list, SOF_IPC_STREAM_PLAYBACK); + if (ret) { + trace_ipc_error("mc5"); + goto dma_cp_err; + } +#else + + ret = dma_copy_set_stream_tag(&dc, ipc_mod->stream_tag); + if (ret < 0) { + trace_ipc_error("mc6"); + goto dma_cp_err; + } + +#endif + + /* set up DMA configuration */ + list_item_prepend(&elem.list, &sg_config.elem_list); + + /* copy module from host */ + ret = dma_copy_from_host(&dc, &sg_config, 0, smod->elf, + ipc_mod->buffer.size); + if (ret < 0) { + trace_ipc_error("mc7"); + goto dma_cp_err; + } + + /* write data back to memory */ + dcache_writeback_region(smod->elf, ipc_mod->buffer.size); + rfree(page_table); + return 0; + +dma_cp_err: + rfree(smod->elf); +mod_buf_err: + rfree(page_table); + return ret; +} + +static int relocate_module(struct sof_module *smod, + struct ipc_module_new *ipc_mod) +{ + int ret; + + /* parse module sections and get text, data, bss sizes */ + ret = arch_elf_parse_sections(smod); + if (ret < 0) { + trace_ipc_error("mr0"); + return ret; + } + + /* allocate memory for text section */ + smod->text = rmalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM | + SOF_MEM_CAPS_CACHE | SOF_MEM_CAPS_EXEC, + smod->text_bytes); + if (!smod->text) { + trace_ipc_error("mr1"); + return -ENOMEM; + } + + /* allocate memory for data section */ + smod->data = rmalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM | + SOF_MEM_CAPS_CACHE, + smod->data_bytes); + if (!smod->text) { + trace_ipc_error("mr2"); + rfree(smod->text); + return -ENOMEM; + } + + /* allocate memory for bss section */ + smod->bss = rmalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM | + SOF_MEM_CAPS_CACHE, + smod->bss_bytes); + if (!smod->text) { + trace_ipc_error("mr3"); + rfree(smod->text); + rfree(smod->data); + return -ENOMEM; + } + + /* relocate module */ + ret = arch_elf_reloc_sections(smod); + if (ret < 0) { + trace_ipc_error("mr4"); + rfree(smod->text); + rfree(smod->data); + rfree(smod->bss); + return ret; + } + + return 0; +} + +struct sof_module *module_init(struct sof *sof, struct ipc_module_new *ipc_mod) +{ + struct sof_module *smod; + int err; + + /* allocate module */ + smod = rzalloc(RZONE_RUNTIME, SOF_MEM_CAPS_RAM, sizeof(*smod)); + if (!smod) { + trace_module_error("mi0"); + return NULL; + } + + /* copy module from host */ + err = copy_module(smod, ipc_mod); + if (!smod) { + trace_module_error("mi1"); + goto copy_err; + } + + /* relocate module */ + err = relocate_module(smod, ipc_mod); + if (!smod) { + trace_module_error("mi2"); + goto reloc_err; + } + + /* probe the module */ + err = smod->drv->init(smod); + if (err < 0) { + trace_module_error("mi3"); + goto reloc_err; + } + + /* compelte init */ + list_item_append(&smod->list, &sof->module_list); + rfree(smod->elf); + + return smod; + +reloc_err: + rfree(smod->text); + rfree(smod->data); + rfree(smod->bss); +copy_err: + rfree(smod->elf); + rfree(smod); + return NULL; +} + +int module_remove(struct sof *sof, struct sof_module *module) +{ + int ret; + + ret = module->drv->exit(module); + list_item_del(&module->list); + rfree(module); + + return ret; +} diff --git a/src/lib/notifier.c b/src/lib/notifier.c index 8a8068b2189b..26e8fc2381ed 100644 --- a/src/lib/notifier.c +++ b/src/lib/notifier.c @@ -48,6 +48,7 @@ void notifier_register(struct notifier *notifier) list_item_prepend(¬ifier->list, &_notify.list); spin_unlock(&_notify.lock); } +EXPORT(notifier_register); void notifier_unregister(struct notifier *notifier) { @@ -55,6 +56,7 @@ void notifier_unregister(struct notifier *notifier) list_item_del(¬ifier->list); spin_unlock(&_notify.lock); } +EXPORT(notifier_unregister); void notifier_event(int id, int message, void *event_data) { @@ -77,6 +79,7 @@ void notifier_event(int id, int message, void *event_data) out: spin_unlock(&_notify.lock); } +EXPORT(notifier_event); void init_system_notify(struct sof *sof) { diff --git a/src/lib/schedule.c b/src/lib/schedule.c index b98934d2bdda..a5adcc38b4fe 100644 --- a/src/lib/schedule.c +++ b/src/lib/schedule.c @@ -280,6 +280,7 @@ void schedule_task_idle(struct task *task, uint64_t deadline) { _schedule_task(task, 0, deadline); } +EXPORT(schedule_task_idle); /* * Add a new task to the scheduler to be run and define a scheduling @@ -301,6 +302,7 @@ void schedule_task(struct task *task, uint64_t start, uint64_t deadline) schedule(); } } +EXPORT(schedule_task); /* Remove a task from the scheduler when complete */ void schedule_task_complete(struct task *task) @@ -314,6 +316,7 @@ void schedule_task_complete(struct task *task) task->state = TASK_STATE_COMPLETED; spin_unlock_irq(&sch->lock, flags); } +EXPORT(schedule_task_complete); static void scheduler_run(void *unused) { @@ -363,6 +366,7 @@ void schedule(void) /* the scheduler is run in IRQ context */ interrupt_set(PLATFORM_SCHEDULE_IRQ); } +EXPORT(schedule); /* Initialise the scheduler */ int scheduler_init(struct sof *sof) diff --git a/src/lib/trace.c b/src/lib/trace.c index 0c378588e5b0..1ccf535365f1 100644 --- a/src/lib/trace.c +++ b/src/lib/trace.c @@ -57,6 +57,7 @@ void _trace_event(uint32_t event) dt[1] = event; dtrace_event((const char *)dt, sizeof(uint64_t) * 2); } +EXPORT(_trace_event); void _trace_event_atomic(uint32_t event) { @@ -69,6 +70,7 @@ void _trace_event_atomic(uint32_t event) dt[1] = event; dtrace_event_atomic((const char *)dt, sizeof(uint64_t) * 2); } +EXPORT(_trace_event_atomic); /* send trace events to the local trace buffer and the mailbox */ void _trace_event_mbox(uint32_t event) @@ -106,6 +108,7 @@ void _trace_event_mbox(uint32_t event) /* writeback trace data */ dcache_writeback_region((void *)t, sizeof(uint64_t) * 2); } +EXPORT(_trace_event_mbox); void _trace_event_mbox_atomic(uint32_t event) { @@ -135,6 +138,7 @@ void _trace_event_mbox_atomic(uint32_t event) /* writeback trace data */ dcache_writeback_region((void *)t, sizeof(uint64_t) * 2); } +EXPORT(_trace_event_mbox_atomic); void trace_flush(void) { @@ -146,11 +150,13 @@ void trace_flush(void) /* flush dma trace messages */ dma_trace_flush((void *)t); } +EXPORT(trace_flush); void trace_off(void) { trace.enable = 0; } +EXPORT(trace_off); void trace_init(struct sof *sof) { diff --git a/src/lib/work.c b/src/lib/work.c index 6b628b5bb9cd..d819ee6da3f9 100644 --- a/src/lib/work.c +++ b/src/lib/work.c @@ -360,11 +360,13 @@ void work_schedule(struct work_queue *queue, struct work *w, uint64_t timeout) out: spin_unlock_irq(&queue->lock, flags); } +EXPORT(work_schedule); void work_schedule_default(struct work *w, uint64_t timeout) { work_schedule(queue_, w, timeout); } +EXPORT(work_schedule_default); static void reschedule(struct work_queue *queue, struct work *w, uint64_t time) { @@ -403,6 +405,7 @@ void work_reschedule(struct work_queue *queue, struct work *w, uint64_t timeout) reschedule(queue, w, time); } +EXPORT(work_reschedule); void work_reschedule_default(struct work *w, uint64_t timeout) { @@ -413,11 +416,13 @@ void work_reschedule_default(struct work *w, uint64_t timeout) reschedule(queue_, w, time); } +EXPORT(work_reschedule_default); void work_reschedule_default_at(struct work *w, uint64_t time) { reschedule(queue_, w, time); } +EXPORT(work_reschedule_default_at); void work_cancel(struct work_queue *queue, struct work *w) { @@ -433,11 +438,13 @@ void work_cancel(struct work_queue *queue, struct work *w) spin_unlock_irq(&queue->lock, flags); } +EXPORT(work_cancel); void work_cancel_default(struct work *w) { work_cancel(queue_, w); } +EXPORT(work_cancel_default); struct work_queue *work_new_queue(struct work_queue_timesource *ts) { @@ -463,6 +470,7 @@ struct work_queue *work_new_queue(struct work_queue_timesource *ts) return queue; } +EXPORT(work_new_queue); void init_system_workq(struct work_queue_timesource *ts) { diff --git a/src/math/numbers.c b/src/math/numbers.c index d7a17171544a..ef5290ee1cac 100644 --- a/src/math/numbers.c +++ b/src/math/numbers.c @@ -35,6 +35,7 @@ * https://en.wikipedia.org/wiki/Euclidean_algorithm#Implementations */ +#include #include int gcd(int a, int b) @@ -47,3 +48,4 @@ int gcd(int a, int b) } return a; } +EXPORT(gcd); diff --git a/src/math/trig.c b/src/math/trig.c index 47770a1d7c00..52bed46d8d1a 100644 --- a/src/math/trig.c +++ b/src/math/trig.c @@ -31,6 +31,7 @@ */ #include +#include #include #include @@ -598,3 +599,4 @@ int32_t sin_fixed(int32_t w) { sine = s0 + q_mults_32x32(frac, delta, Q_SHIFT_BITS_64(31, 31, 31)); return (int32_t) sine; } +EXPORT(sin_fixed); diff --git a/src/modules/Makefile.am b/src/modules/Makefile.am new file mode 100644 index 000000000000..3315e4bbb327 --- /dev/null +++ b/src/modules/Makefile.am @@ -0,0 +1,2 @@ +SUBDIRS = \ + template diff --git a/src/modules/template/Makefile.am b/src/modules/template/Makefile.am new file mode 100644 index 000000000000..653ed3eb347b --- /dev/null +++ b/src/modules/template/Makefile.am @@ -0,0 +1,22 @@ +all: template.ro + +# all module file individially built and then linked below +template.o: template.c + $(CC) $(CFLAGS) $(COMMON_INCDIR) -c template.c module.c + +# used by rimage for module loading/signing +module.o: module.c + $(CC) $(CFLAGS) $(COMMON_INCDIR) -c module.c + +# link all object files togetether into SOF module +template.ro: module.o template.o + $(LD) -r module.o template.o -o template.ro.debug + $(OBJCOPY) --strip-debug --strip-unneeded template.ro.debug template.ro + +clean-local: + rm -fr *.o + rm -fr *.ro + rm -fr *.debug + +bin-local: + rimage -o template-$(FW_NAME).rm -m $(FW_NAME) -r template.ro \ No newline at end of file diff --git a/src/modules/template/module.c b/src/modules/template/module.c new file mode 100644 index 000000000000..4a85071a6640 --- /dev/null +++ b/src/modules/template/module.c @@ -0,0 +1,55 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#include +#include + +SOF_MODULE_DECL(template); + +/* + * Each module has an entry in the FW manifest header. This is NOT part of + * the SOF executable image but is inserted by object copy as a ELF section + * for parsing by rimage (to generate the manifest). + */ +const struct sof_man_module_manifest __attribute__((used)) __attribute__((section(".module"), used)) template_manifest = { + .module = { + .name = "TEMPLATE", + .uuid = {0x32, 0x8c, 0x39, 0x0e, 0xde, 0x5a, 0x4b, 0xba, + 0x93, 0xb1, 0xc5, 0x04, 0x32, 0x28, 0x0e, 0xe4}, + .entry_point = SOF_MODULE_REF(template), + .type = { + .load_type = SOF_MAN_MOD_TYPE_MODULE, + .domain_ll = 1, + }, + .affinity_mask = 3, + }, +}; + + diff --git a/src/modules/template/template.c b/src/modules/template/template.c new file mode 100644 index 000000000000..2e16c9617410 --- /dev/null +++ b/src/modules/template/template.c @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2016, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + */ + +#include +#include +#include +#include + +/* tracing */ +#define trace_template(__e) trace_event(TRACE_CLASS_VOLUME, __e) +#define trace_template_error(__e) trace_error(TRACE_CLASS_VOLUME, __e) +#define tracev_template(__e) tracev_event(TRACE_CLASS_VOLUME, __e) + +static struct comp_dev *template_new(struct sof_ipc_comp *comp) +{ + trace_template("new"); + + return NULL; +} + +static void template_free(struct comp_dev *dev) +{ + trace_template("fre"); +} + +/* set component audio stream parameters */ +static int template_params(struct comp_dev *dev) +{ + + return 0; +} + +/* used to pass standard and bespoke commands (with data) to component */ +static int template_cmd(struct comp_dev *dev, int cmd, void *data) +{ + /* template will use buffer "connected" status */ + return 0; +} + +/* copy and process stream data from source to sink buffers */ +static int template_copy(struct comp_dev *dev) +{ + + return 0; +} + +static int template_reset(struct comp_dev *dev) +{ + return 0; +} + +static int template_prepare(struct comp_dev *dev) +{ + return 0; +} + +struct comp_driver comp_template = { + .type = SOF_COMP_VOLUME, + .ops = { + .new = template_new, + .free = template_free, + .params = template_params, + .cmd = template_cmd, + .copy = template_copy, + .prepare = template_prepare, + .reset = template_reset, + }, +}; + +static int template_init(struct sof_module *mod) +{ + comp_register(&comp_template); + return 0; +} + +static int template_exit(struct sof_module *mod) +{ + comp_unregister(&comp_template); + return 0; +} + +SOF_MODULE(template, template_init, template_exit); diff --git a/src/platform/apollolake/apollolake.x.in b/src/platform/apollolake/apollolake.x.in index 76fbeb7c3b2d..8ee2a919e2e9 100644 --- a/src/platform/apollolake/apollolake.x.in +++ b/src/platform/apollolake/apollolake.x.in @@ -389,6 +389,17 @@ SECTIONS LONG(_bss_start) LONG(_bss_end) _bss_table_end = ABSOLUTE(.); + . = ALIGN(4); + _symbol_strings_start = ABSOLUTE(.); + LONG(_symbol_strings_start) + *(._symbol_strings) + LONG(_symbol_strings_end) + _symbol_strings_end = ABSOLUTE(.); + _symbol_table_start = ABSOLUTE(.); + LONG(_symbol_table_start) + *(._symbol_table) + LONG(_symbol_table_end) + _symbol_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); } >sof_data :sof_data_phdr diff --git a/src/platform/apollolake/include/platform/memory.h b/src/platform/apollolake/include/platform/memory.h index c71d8c6cfa93..cf214247cb88 100644 --- a/src/platform/apollolake/include/platform/memory.h +++ b/src/platform/apollolake/include/platform/memory.h @@ -171,7 +171,7 @@ #define SOF_TEXT_SIZE 0x19000 /* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000 /* bss data */ #define SOF_BSS_DATA_SIZE 0x2800 diff --git a/src/platform/apollolake/include/platform/platform.h b/src/platform/apollolake/include/platform/platform.h index 8503ce251710..498cd1ddc2ea 100644 --- a/src/platform/apollolake/include/platform/platform.h +++ b/src/platform/apollolake/include/platform/platform.h @@ -115,6 +115,9 @@ struct sof; /* number of SSP ports in platform */ #define PLATFORM_NUM_SSP 6 +/* ISA code for module compliance */ +#define PLATFORM_ISA {'a', 'p', 'l', '0'} + /* Platform defined panic code */ #define platform_panic(__x) { \ sw_reg_write(SRAM_REG_FW_STATUS, (0xdead000 | __x) & 0x3fffffff); \ diff --git a/src/platform/baytrail/baytrail.x.in b/src/platform/baytrail/baytrail.x.in index 0dd45050fc0b..81b680bf2325 100755 --- a/src/platform/baytrail/baytrail.x.in +++ b/src/platform/baytrail/baytrail.x.in @@ -365,6 +365,17 @@ SECTIONS LONG(_bss_start) LONG(_bss_end) _bss_table_end = ABSOLUTE(.); + . = ALIGN(4); + _symbol_strings_start = ABSOLUTE(.); + LONG(_symbol_strings_start) + *(._symbol_strings) + LONG(_symbol_strings_end) + _symbol_strings_end = ABSOLUTE(.); + _symbol_table_start = ABSOLUTE(.); + LONG(_symbol_table_start) + *(._symbol_table) + LONG(_symbol_table_end) + _symbol_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); } >sof_data :sof_data_phdr diff --git a/src/platform/baytrail/include/platform/platform.h b/src/platform/baytrail/include/platform/platform.h index 4d32d5e908e3..fbe93d2e5b96 100644 --- a/src/platform/baytrail/include/platform/platform.h +++ b/src/platform/baytrail/include/platform/platform.h @@ -100,6 +100,9 @@ struct sof; /* DSP should be idle in this time frame */ #define PLATFORM_IDLE_TIME 750000 +/* ISA code for module compliance */ +#define PLATFORM_ISA {'b', 'y', 't', '0'} + /* Platform defined panic code */ #define platform_panic(__x) { \ shim_write(SHIM_IPCDL, (0xdead000 | (__x & 0xfff))); \ diff --git a/src/platform/cannonlake/cannonlake.x.in b/src/platform/cannonlake/cannonlake.x.in index 052d637841b3..21addf9769e8 100644 --- a/src/platform/cannonlake/cannonlake.x.in +++ b/src/platform/cannonlake/cannonlake.x.in @@ -390,6 +390,17 @@ SECTIONS LONG(_bss_start) LONG(_bss_end) _bss_table_end = ABSOLUTE(.); + . = ALIGN(4); + _symbol_strings_start = ABSOLUTE(.); + LONG(_symbol_strings_start) + *(._symbol_strings) + LONG(_symbol_strings_end) + _symbol_strings_end = ABSOLUTE(.); + _symbol_table_start = ABSOLUTE(.); + LONG(_symbol_table_start) + *(._symbol_table) + LONG(_symbol_table_end) + _symbol_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); } >sof_data :sof_data_phdr diff --git a/src/platform/cannonlake/include/platform/memory.h b/src/platform/cannonlake/include/platform/memory.h index c7f475040ba6..67f574ae6e2c 100644 --- a/src/platform/cannonlake/include/platform/memory.h +++ b/src/platform/cannonlake/include/platform/memory.h @@ -240,7 +240,7 @@ #define SOF_TEXT_SIZE 0x18000 /* initialized data */ -#define SOF_DATA_SIZE 0x18000 +#define SOF_DATA_SIZE 0x19000 /* bss data */ #define SOF_BSS_DATA_SIZE 0x8000 diff --git a/src/platform/cannonlake/include/platform/platform.h b/src/platform/cannonlake/include/platform/platform.h index c5bf42a664f0..3f35832caf93 100644 --- a/src/platform/cannonlake/include/platform/platform.h +++ b/src/platform/cannonlake/include/platform/platform.h @@ -110,6 +110,9 @@ struct sof; /* DSP should be idle in this time frame */ #define PLATFORM_IDLE_TIME 750000 +/* ISA code for module compliance */ +#define PLATFORM_ISA {'c', 'n', 'l', '0'} + /* Platform defined trace code */ #define platform_panic(__x) { \ sw_reg_write(SRAM_REG_FW_STATUS, (0xdead000 | __x) & 0x3fffffff); \ diff --git a/src/platform/haswell/broadwell.x.in b/src/platform/haswell/broadwell.x.in index 9551eb67a7b6..d671d602ffee 100755 --- a/src/platform/haswell/broadwell.x.in +++ b/src/platform/haswell/broadwell.x.in @@ -365,6 +365,17 @@ SECTIONS LONG(_bss_start) LONG(_bss_end) _bss_table_end = ABSOLUTE(.); + . = ALIGN(4); + _symbol_strings_start = ABSOLUTE(.); + LONG(_symbol_strings_start) + *(._symbol_strings) + LONG(_symbol_strings_end) + _symbol_strings_end = ABSOLUTE(.); + _symbol_table_start = ABSOLUTE(.); + LONG(_symbol_table_start) + *(._symbol_table) + LONG(_symbol_table_end) + _symbol_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); } >sof_data :sof_data_phdr diff --git a/src/platform/haswell/haswell.x.in b/src/platform/haswell/haswell.x.in index 8733bfca0edc..190e6a6b5647 100755 --- a/src/platform/haswell/haswell.x.in +++ b/src/platform/haswell/haswell.x.in @@ -365,6 +365,17 @@ SECTIONS LONG(_bss_start) LONG(_bss_end) _bss_table_end = ABSOLUTE(.); + . = ALIGN(4); + _symbol_strings_start = ABSOLUTE(.); + LONG(_symbol_strings_start) + *(._symbol_strings) + LONG(_symbol_strings_end) + _symbol_strings_end = ABSOLUTE(.); + _symbol_table_start = ABSOLUTE(.); + LONG(_symbol_table_start) + *(._symbol_table) + LONG(_symbol_table_end) + _symbol_table_end = ABSOLUTE(.); _rodata_end = ABSOLUTE(.); } >sof_data :sof_data_phdr diff --git a/src/platform/haswell/include/platform/platform.h b/src/platform/haswell/include/platform/platform.h index abe4c84f6905..a298f6555818 100644 --- a/src/platform/haswell/include/platform/platform.h +++ b/src/platform/haswell/include/platform/platform.h @@ -99,6 +99,9 @@ struct sof; /* DSP should be idle in this time frame */ #define PLATFORM_IDLE_TIME 750000 +/* ISA code for module compliance */ +#define PLATFORM_ISA {'h', 's', 'w', '0'} + /* Platform defined panic code */ #define platform_panic(__x) \ shim_write(SHIM_IPCD, (SHIM_IPCD_BUSY | 0xdead000 | __x)) diff --git a/src/test/Makefile.am b/src/test/Makefile.am new file mode 100644 index 000000000000..61f82ab2c92c --- /dev/null +++ b/src/test/Makefile.am @@ -0,0 +1 @@ +SUBDIRS = linker \ No newline at end of file diff --git a/src/test/linker/Makefile.am b/src/test/linker/Makefile.am new file mode 100644 index 000000000000..a35739e8ed98 --- /dev/null +++ b/src/test/linker/Makefile.am @@ -0,0 +1,8 @@ +bin_PROGRAMS = \ + sof_linker + +sof_linker_SOURCES = \ + ../../arch/xtensa/reloc.c \ + linker.c + +sof_linker_CFLAGS = ${COMMON_INCDIR} -I ../../arch/xtensa/include \ No newline at end of file diff --git a/src/test/linker/linker.c b/src/test/linker/linker.c new file mode 100644 index 000000000000..e0ede0ae0bf0 --- /dev/null +++ b/src/test/linker/linker.c @@ -0,0 +1,88 @@ +/* + * Copyright (c) 2018, Intel Corporation + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * * Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * * Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * * Neither the name of the Intel Corporation nor the + * names of its contributors may be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + * + * Author: Liam Girdwood + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +int main(int argc, char *argv[]) +{ + struct reloc reloc; + size_t count; + int ret = 0; + long file_size; + + bzero(&reloc, sizeof(reloc)); + + /* open the elf input file */ + reloc.fd = fopen(argv[1], "r"); + if (reloc.fd == NULL) { + fprintf(stderr, "error: unable to open %s for reading %d\n", + argv[1], errno); + return -EINVAL; + } + + fseek(reloc.fd, 0, SEEK_END); + file_size = ftell(reloc.fd); + + reloc.elf = calloc(file_size, 1); + if (reloc.elf == NULL) + return -errno; + + /* read in elf header */ + fseek(reloc.fd, 0, SEEK_SET); + count = fread(reloc.elf, file_size, 1, reloc.fd); + if (count != 1) { + fprintf(stderr, "error: failed to read %s elf file %d\n", + argv[1], -errno); + return -errno; + } + + /* read sections */ + ret = reloc_mod(&reloc); + if (ret < 0) { + fprintf(stderr, "error: failed to read base sections %d\n", + ret); + } + + return 0; + +hdr_err: + fclose(reloc.fd); + + return ret; +}