From 45e6b91f99de545db64c3cf6a8115830cc6eb6be Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 11 Apr 2018 16:53:02 +0100 Subject: [PATCH 01/12] ipc: page tables; Make page table API generic for use outside IPC core Allow users outside of IPC to make use of compressed host page tables. Signed-off-by: Liam Girdwood --- src/include/sof/intel-ipc.h | 1 - src/include/sof/ipc.h | 8 ++ src/ipc/handler.c | 143 +++--------------------------------- src/ipc/ipc.c | 129 ++++++++++++++++++++++++++++++++ 4 files changed, 146 insertions(+), 135 deletions(-) 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/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/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; From 804e29002845142df45d2805948a56bf6dbe0724 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Apr 2018 16:33:56 +0100 Subject: [PATCH 02/12] core: symbols: Add support for building a symbol table. Build a symbol table to support runtime loading and linking of external modules. This can be enabled/disabled via configure. Signed-off-by: Liam Girdwood --- src/include/sof/sof.h | 24 +++++++++++++++++++ src/platform/apollolake/apollolake.x.in | 11 +++++++++ .../apollolake/include/platform/memory.h | 2 +- src/platform/baytrail/baytrail.x.in | 11 +++++++++ src/platform/cannonlake/cannonlake.x.in | 11 +++++++++ .../cannonlake/include/platform/memory.h | 2 +- src/platform/haswell/broadwell.x.in | 11 +++++++++ src/platform/haswell/haswell.x.in | 11 +++++++++ 8 files changed, 81 insertions(+), 2 deletions(-) diff --git a/src/include/sof/sof.h b/src/include/sof/sof.h index b9d7aff0419f..3ab29f1bf6b9 100644 --- a/src/include/sof/sof.h +++ b/src/include/sof/sof.h @@ -44,6 +44,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 */ 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/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/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/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 From ebc9286f2713812261a8befa0acc668cca6f4471 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Apr 2018 16:37:41 +0100 Subject: [PATCH 03/12] core: symbols: Export common functions into symbol table Export commonly used functions into the symbol table. Signed-off-by: Liam Girdwood --- src/ipc/apl-ipc.c | 1 + src/ipc/byt-ipc.c | 1 + src/ipc/cnl-ipc.c | 1 + src/ipc/dma-copy.c | 6 ++++++ src/ipc/hsw-ipc.c | 1 + src/lib/agent.c | 1 + src/lib/alloc.c | 4 ++++ src/lib/interrupt.c | 4 ++++ src/lib/lib.c | 5 +++++ src/lib/notifier.c | 3 +++ src/lib/schedule.c | 4 ++++ src/lib/trace.c | 6 ++++++ src/lib/work.c | 8 ++++++++ src/math/numbers.c | 2 ++ src/math/trig.c | 2 ++ 15 files changed, 49 insertions(+) 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/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/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/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); From 2f2e30fb242482a0431b43f1ca882157148ad21b Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Apr 2018 16:42:36 +0100 Subject: [PATCH 04/12] core: linker: Add runtime linker for xtensa architecture Add a runtime module linker for the xtensa architecture. This will support loading external modules at runtime and linking them with symbols in the symbol table. Signed-off-by: Liam Girdwood --- src/arch/xtensa/Makefile.am | 3 +- src/arch/xtensa/include/arch/Makefile.am | 1 + src/arch/xtensa/include/arch/reloc.h | 42 +++ src/arch/xtensa/reloc.c | 365 +++++++++++++++++++++++ src/include/sof/Makefile.am | 1 + src/include/sof/module.h | 188 ++++++++++++ src/include/uapi/ipc.h | 10 + 7 files changed, 609 insertions(+), 1 deletion(-) create mode 100644 src/arch/xtensa/include/arch/reloc.h create mode 100644 src/arch/xtensa/reloc.c create mode 100644 src/include/sof/module.h 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..f635fec5c6ec --- /dev/null +++ b/src/arch/xtensa/reloc.c @@ -0,0 +1,365 @@ +/* + * 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 + +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 section *section, + struct rela *rela) +{ + struct elf32_symbol *sym; + uint32_t addr; + int i; + int num_relocs; + const char *symbol_name; + + /* 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++) { + + /* make sure relocation is valid type */ + if (ELF32_R_TYPE(rela->item[i].r_info) == R_XTENSA_SLOT0_OP) + continue; + if (ELF32_R_TYPE(rela->item[i].r_info) == R_XTENSA_ASM_EXPAND) + continue; + + /* get symbol table entry for relocaton */ + sym = &reloc->symbol[ELF32_R_SYM(rela->item[i].r_info)]; + + /* symbol must have a name TODO: misses data */ + if (sym->st_name == 0) + continue; + + /* symbol must be global */ + if (ELF32_ST_BIND(sym->st_info) != STB_GLOBAL) + continue; + + /* get symbol name */ + symbol_name = elf_get_string(reloc, sym->st_name); + if (!symbol_name) + return -EINVAL; + + /* get symbol address */ + addr = elf_get_symbol_addr(reloc, symbol_name); + if (addr == 0) + return -EINVAL; + + /* add text value to address at offset */ + *((uint32_t *)(section->data + rela->item[i].r_offset)) = + addr + rela->item[i].r_addend; + } + + 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 i; + int ret; + + /* relocate each section */ + for (i = SOF_DATA_SECTION; i <= SOF_TEXT_SECTION; i++) { + ret = elf_reloc_section(reloc, &reloc->section[i], + &reloc->rela[i]); + 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/module.h b/src/include/sof/module.h new file mode 100644 index 000000000000..0f6d338c1f75 --- /dev/null +++ b/src/include/sof/module.h @@ -0,0 +1,188 @@ +/* + * 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_32_PCREL 14 +#define R_XTENSA_SLOT0_OP 20 +#define R_XTENSA_ASM_EXPAND 11 + +/* 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/uapi/ipc.h b/src/include/uapi/ipc.h index fbf1c072865f..43977a858297 100644 --- a/src/include/uapi/ipc.h +++ b/src/include/uapi/ipc.h @@ -727,6 +727,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 */ From 946ad2a7d9dcd899350def188b3955ea60c75c83 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Fri, 6 Apr 2018 16:53:01 +0100 Subject: [PATCH 05/12] core: modules: Add external module template Template code showing how to create an external module. Signed-off-by: Liam Girdwood --- .gitignore | 5 + configure.ac | 2 + src/Makefile.am | 2 +- src/include/sof/sof.h | 5 + src/include/sof/trace.h | 1 + src/lib/Makefile.am | 3 +- src/lib/module.c | 253 +++++++++++++++++++++++++++++++ src/modules/Makefile.am | 2 + src/modules/template/Makefile.am | 20 +++ src/modules/template/module.c | 56 +++++++ src/modules/template/template.c | 109 +++++++++++++ 11 files changed, 456 insertions(+), 2 deletions(-) create mode 100644 src/lib/module.c create mode 100644 src/modules/Makefile.am create mode 100644 src/modules/template/Makefile.am create mode 100644 src/modules/template/module.c create mode 100644 src/modules/template/template.c 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..6d73473f43c6 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 diff --git a/src/Makefile.am b/src/Makefile.am index 331dd0d66dbc..10f65b12cece 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -8,5 +8,5 @@ SUBDIRS = ipc math audio arch include library 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/include/sof/sof.h b/src/include/sof/sof.h index 3ab29f1bf6b9..cb4d77dbf0fb 100644 --- a/src/include/sof/sof.h +++ b/src/include/sof/sof.h @@ -33,6 +33,7 @@ #include #include +#include #include struct ipc; @@ -82,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/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/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/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..e5147cfe95d4 --- /dev/null +++ b/src/modules/template/Makefile.am @@ -0,0 +1,20 @@ +modules: template.sof + +# 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.sof: module.o template.o + $(LD) -r module.o template.o -o template.sof + +clean-local: + rm -fr *.o + +bin-local: + ls +#rimage \ 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..df5b46c15e3e --- /dev/null +++ b/src/modules/template/module.c @@ -0,0 +1,56 @@ +/* + * 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 "template.h" + +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("_manifest"), 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..e9dda40881f2 --- /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_dev *dev) +{ + comp_register(&comp_template); + return 0; +} + +static int template_exit(struct sof_module_dev *dev) +{ + comp_unregister(&comp_template); + return 0; +} + +SOF_MODULE(template, template_init, template_exit); From 5e59c6ebe01b7f6e4b62d8c511f123fef74eda06 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:07:35 +0100 Subject: [PATCH 06/12] rimage: add support to build and sign runtime modules Currently rimage only supports building ELF images with know TEXT, DATA and BSS addresses. This patch adds support to build runtime relocatable modules that can be loaded linked into the base SOF FW at runtime. Signed-off-by: Liam Girdwood --- rimage/elf.c | 72 ++++++++++++++++++++++++++++---- rimage/file_simple.c | 97 ++++++++++++++++++++++++++++++++++++++++++- rimage/manifest.c | 99 +++++++++++++++++++++++++++++++++++++++++++- rimage/rimage.c | 9 +++- rimage/rimage.h | 4 ++ 5 files changed, 268 insertions(+), 13 deletions(-) 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 */ From 2f29d8920cb3a306c9a75b209adcbec3004b4635 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:12:33 +0100 Subject: [PATCH 07/12] uapi: ipc: Add executable memory flag Add flag to mark memory as executable. Signed-off-by: Liam Girdwood --- src/include/uapi/ipc.h | 1 + 1 file changed, 1 insertion(+) diff --git a/src/include/uapi/ipc.h b/src/include/uapi/ipc.h index 43977a858297..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. From f216fa86b3ed10ab21bceadcadc77c906e3fe42c Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:18:58 +0100 Subject: [PATCH 08/12] host: linker: Add relocator stubs - WIP Signed-off-by: Liam Girdwood --- src/arch/host/include/arch/Makefile.am | 3 + src/arch/host/include/arch/atomic.h | 77 ++++++++++++++++++++++++++ src/arch/host/include/arch/reloc.h | 42 ++++++++++++++ src/arch/host/include/arch/task.h | 43 ++++++++++++++ 4 files changed, 165 insertions(+) create mode 100644 src/arch/host/include/arch/atomic.h create mode 100644 src/arch/host/include/arch/reloc.h create mode 100644 src/arch/host/include/arch/task.h 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 From b6f79d0bc3025a740a5e7c7568e389ad2f8eb0f2 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:25:58 +0100 Subject: [PATCH 09/12] test: Add unit test for runtime linker. Signed-off-by: Liam Girdwood --- configure.ac | 2 + src/Makefile.am | 2 +- src/test/Makefile.am | 1 + src/test/linker/Makefile.am | 8 ++++ src/test/linker/linker.c | 88 +++++++++++++++++++++++++++++++++++++ 5 files changed, 100 insertions(+), 1 deletion(-) create mode 100644 src/test/Makefile.am create mode 100644 src/test/linker/Makefile.am create mode 100644 src/test/linker/linker.c diff --git a/configure.ac b/configure.ac index 6d73473f43c6..277a47f32139 100644 --- a/configure.ac +++ b/configure.ac @@ -387,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/src/Makefile.am b/src/Makefile.am index 10f65b12cece..b8d0768bd7ff 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -4,7 +4,7 @@ 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 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; +} From 18547efdf3966dff1c3320cb813ca0540e2e244f Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:28:33 +0100 Subject: [PATCH 10/12] module: Add template module. This module does nothing but can be copied as template code. Signed-off-by: Liam Girdwood --- src/modules/template/Makefile.am | 12 +++++++----- src/modules/template/module.c | 3 +-- src/modules/template/template.c | 4 ++-- 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/src/modules/template/Makefile.am b/src/modules/template/Makefile.am index e5147cfe95d4..653ed3eb347b 100644 --- a/src/modules/template/Makefile.am +++ b/src/modules/template/Makefile.am @@ -1,4 +1,4 @@ -modules: template.sof +all: template.ro # all module file individially built and then linked below template.o: template.c @@ -9,12 +9,14 @@ module.o: module.c $(CC) $(CFLAGS) $(COMMON_INCDIR) -c module.c # link all object files togetether into SOF module -template.sof: module.o template.o - $(LD) -r module.o template.o -o template.sof +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: - ls -#rimage \ No newline at end of file + 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 index df5b46c15e3e..4a85071a6640 100644 --- a/src/modules/template/module.c +++ b/src/modules/template/module.c @@ -30,7 +30,6 @@ #include #include -#include "template.h" SOF_MODULE_DECL(template); @@ -39,7 +38,7 @@ SOF_MODULE_DECL(template); * 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("_manifest"), used)) template_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, diff --git a/src/modules/template/template.c b/src/modules/template/template.c index e9dda40881f2..2e16c9617410 100644 --- a/src/modules/template/template.c +++ b/src/modules/template/template.c @@ -94,13 +94,13 @@ struct comp_driver comp_template = { }, }; -static int template_init(struct sof_module_dev *dev) +static int template_init(struct sof_module *mod) { comp_register(&comp_template); return 0; } -static int template_exit(struct sof_module_dev *dev) +static int template_exit(struct sof_module *mod) { comp_unregister(&comp_template); return 0; From 595b8bc023a04d1cf9f69eea2829f70f9d3aab78 Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Thu, 12 Apr 2018 21:30:06 +0100 Subject: [PATCH 11/12] module platf isa Signed-off-by: Liam Girdwood --- src/platform/apollolake/include/platform/platform.h | 3 +++ src/platform/baytrail/include/platform/platform.h | 3 +++ src/platform/cannonlake/include/platform/platform.h | 3 +++ src/platform/haswell/include/platform/platform.h | 3 +++ 4 files changed, 12 insertions(+) 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/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/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/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)) From 2c92275d3fb3eedbb54ebe401351fa1f9a27d9fc Mon Sep 17 00:00:00 2001 From: Liam Girdwood Date: Wed, 18 Apr 2018 09:35:26 -0700 Subject: [PATCH 12/12] xtensa: reloc: Add more support for other reloc types. To be squashed. Signed-off-by: Liam Girdwood --- src/arch/xtensa/reloc.c | 141 ++++++++++++++++++++++++++++----------- src/include/sof/module.h | 8 ++- 2 files changed, 108 insertions(+), 41 deletions(-) diff --git a/src/arch/xtensa/reloc.c b/src/arch/xtensa/reloc.c index f635fec5c6ec..2a9766290bb4 100644 --- a/src/arch/xtensa/reloc.c +++ b/src/arch/xtensa/reloc.c @@ -38,6 +38,12 @@ #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; @@ -94,14 +100,85 @@ static inline uint32_t elf_get_symbol_addr(struct reloc *reloc, return 0; } -static int elf_reloc_section(struct reloc *reloc, struct section *section, - struct rela *rela) +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; - uint32_t addr; int i; int num_relocs; - const char *symbol_name; + int err; /* make sure section and relocation tables exist */ if (section == NULL || section->shdr == NULL) @@ -114,36 +191,13 @@ static int elf_reloc_section(struct reloc *reloc, struct section *section, /* for each relocation */ for (i = 0; i < num_relocs; i++) { - /* make sure relocation is valid type */ - if (ELF32_R_TYPE(rela->item[i].r_info) == R_XTENSA_SLOT0_OP) - continue; - if (ELF32_R_TYPE(rela->item[i].r_info) == R_XTENSA_ASM_EXPAND) - continue; - - /* get symbol table entry for relocaton */ + /* get symbol table entry for relocation */ sym = &reloc->symbol[ELF32_R_SYM(rela->item[i].r_info)]; - /* symbol must have a name TODO: misses data */ - if (sym->st_name == 0) - continue; - - /* symbol must be global */ - if (ELF32_ST_BIND(sym->st_info) != STB_GLOBAL) - continue; - - /* get symbol name */ - symbol_name = elf_get_string(reloc, sym->st_name); - if (!symbol_name) - return -EINVAL; - - /* get symbol address */ - addr = elf_get_symbol_addr(reloc, symbol_name); - if (addr == 0) - return -EINVAL; - - /* add text value to address at offset */ - *((uint32_t *)(section->data + rela->item[i].r_offset)) = - addr + rela->item[i].r_addend; + err = elf_reloc_section(reloc, &rela->item[i], sym, + section_base); + if (err < 0) + return err; } return 0; @@ -320,16 +374,23 @@ int arch_elf_parse_sections(struct sof_module *smod) int arch_elf_reloc_sections(struct sof_module *smod) { - int i; int ret; - /* relocate each section */ - for (i = SOF_DATA_SECTION; i <= SOF_TEXT_SECTION; i++) { - ret = elf_reloc_section(reloc, &reloc->section[i], - &reloc->rela[i]); - if (ret < 0) - goto err; - } + /* 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, diff --git a/src/include/sof/module.h b/src/include/sof/module.h index 0f6d338c1f75..396b53fda337 100644 --- a/src/include/sof/module.h +++ b/src/include/sof/module.h @@ -89,9 +89,15 @@ struct elf32_section_hdr { #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 -#define R_XTENSA_ASM_EXPAND 11 /* ELF 32bit relocation entry */ struct elf32_relocation {