diff --git a/apps/codecs.c b/apps/codecs.c index 35f6363986..3fa05be59a 100644 --- a/apps/codecs.c +++ b/apps/codecs.c @@ -181,7 +181,8 @@ void codec_get_full_path(char *path, const char *codec_root_fn) static int codec_load_ram(void *handle, struct codec_api *api) { - struct codec_header *hdr = lc_get_header(handle); + struct codec_header *c_hdr = lc_get_header(handle); + struct lc_header *hdr = c_hdr ? &c_hdr->lc_hdr : NULL; int status; if (hdr == NULL @@ -215,8 +216,8 @@ static int codec_load_ram(void *handle, struct codec_api *api) codec_size = 0; #endif - *(hdr->api) = api; - status = hdr->entry_point(); + *(c_hdr->api) = api; + status = c_hdr->entry_point(); lc_close(handle); diff --git a/apps/codecs.h b/apps/codecs.h index f94c81ab20..1c0b9da6ba 100644 --- a/apps/codecs.h +++ b/apps/codecs.h @@ -51,6 +51,7 @@ #include "settings.h" #include "gcc_extensions.h" +#include "load_code.h" #ifdef CODEC #if defined(DEBUG) || defined(SIMULATOR) @@ -240,11 +241,7 @@ struct codec_api { /* codec header */ struct codec_header { - unsigned long magic; /* RCOD or RENC */ - unsigned short target_id; - unsigned short api_version; - unsigned char *load_addr; - unsigned char *end_addr; + struct lc_header lc_hdr; /* must be first */ enum codec_status(*entry_point)(void); struct codec_api **api; }; @@ -261,27 +258,27 @@ extern unsigned char plugin_end_addr[]; #define CODEC_HEADER \ const struct codec_header __header \ __attribute__ ((section (".header")))= { \ - CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ - plugin_start_addr, plugin_end_addr, codec_start, &ci }; + { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ + plugin_start_addr, plugin_end_addr }, codec_start, &ci }; /* encoders */ #define CODEC_ENC_HEADER \ const struct codec_header __header \ __attribute__ ((section (".header")))= { \ - CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ - plugin_start_addr, plugin_end_addr, codec_start, &ci }; + { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ + plugin_start_addr, plugin_end_addr }, codec_start, &ci }; #else /* def SIMULATOR */ /* decoders */ #define CODEC_HEADER \ const struct codec_header __header \ __attribute__((visibility("default"))) = { \ - CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ - NULL, NULL, codec_start, &ci }; + { CODEC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ + codec_start, &ci }; /* encoders */ #define CODEC_ENC_HEADER \ const struct codec_header __header = { \ - CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, \ - NULL, NULL, codec_start, &ci }; + { CODEC_ENC_MAGIC, TARGET_ID, CODEC_API_VERSION, NULL, NULL }, \ + codec_start, &ci }; #endif /* SIMULATOR */ #endif /* CODEC */ diff --git a/apps/codecs/codec_crt0.c b/apps/codecs/codec_crt0.c index fdb79092f4..c845f79a40 100644 --- a/apps/codecs/codec_crt0.c +++ b/apps/codecs/codec_crt0.c @@ -20,15 +20,10 @@ ****************************************************************************/ #include "config.h" -#include "codeclib.h" +#include "codecs.h" struct codec_api *ci DATA_ATTR; -extern unsigned char iramcopy[]; -extern unsigned char iramstart[]; -extern unsigned char iramend[]; -extern unsigned char iedata[]; -extern unsigned char iend[]; extern unsigned char plugin_bss_start[]; extern unsigned char plugin_end_addr[]; @@ -42,14 +37,23 @@ enum codec_status codec_start(void) { #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #ifdef USE_IRAM - ci->memcpy(iramstart, iramcopy, iramend - iramstart); - ci->memset(iedata, 0, iend - iedata); -#endif + extern char iramcopy[], iramstart[], iramend[], iedata[], iend[]; + size_t iram_size = iramend - iramstart; + size_t ibss_size = iend - iedata; + if (iram_size > 0 || ibss_size > 0) + { + ci->memcpy(iramstart, iramcopy, iram_size); + ci->memset(iedata, 0, ibss_size); + /* make the icache (if it exists) up to date with the new code */ + ci->cpucache_invalidate(); + /* barrier to prevent reordering iram copy and BSS clearing, + * because the BSS segment alias the IRAM copy. + */ + asm volatile ("" ::: "memory"); + } +#endif /* PLUGIN_USE_IRAM */ ci->memset(plugin_bss_start, 0, plugin_end_addr - plugin_bss_start); #endif - /* writeback cleared iedata and bss areas, invalidate icache for - * copied code */ - ci->cpucache_invalidate(); return codec_main(); } diff --git a/apps/plugin.c b/apps/plugin.c index 9e08951828..9b490d0fa9 100644 --- a/apps/plugin.c +++ b/apps/plugin.c @@ -723,12 +723,18 @@ static const struct plugin_api rockbox_api = { /* new stuff at the end, sort into place next time the API gets incompatible */ dir_get_info, + + lc_open, + lc_open_from_mem, + lc_get_header, + lc_close, }; int plugin_load(const char* plugin, const void* parameter) { int rc, i; - struct plugin_header *hdr; + struct plugin_header *p_hdr; + struct lc_header *hdr; #if LCD_DEPTH > 1 fb_data* old_backdrop; @@ -754,7 +760,10 @@ int plugin_load(const char* plugin, const void* parameter) return -1; } - hdr = lc_get_header(current_plugin_handle); + p_hdr = lc_get_header(current_plugin_handle); + + hdr = p_hdr ? &p_hdr->lc_hdr : NULL; + if (hdr == NULL || hdr->magic != PLUGIN_MAGIC @@ -782,7 +791,7 @@ int plugin_load(const char* plugin, const void* parameter) plugin_size = 0; #endif - *(hdr->api) = &rockbox_api; + *(p_hdr->api) = &rockbox_api; #if defined HAVE_LCD_BITMAP && LCD_DEPTH > 1 old_backdrop = lcd_get_backdrop(); @@ -806,7 +815,7 @@ int plugin_load(const char* plugin, const void* parameter) open_files = 0; #endif - rc = hdr->entry_point(parameter); + rc = p_hdr->entry_point(parameter); if (!pfn_tsr_exit) { /* close handle if plugin is no tsr one */ diff --git a/apps/plugin.h b/apps/plugin.h index bafd4070f6..a69b85bbfd 100644 --- a/apps/plugin.h +++ b/apps/plugin.h @@ -53,6 +53,7 @@ void* plugin_get_buffer(size_t *buffer_size); #include "thread.h" #include "button.h" #include "action.h" +#include "load_code.h" #include "usb.h" #include "font.h" #include "lcd.h" @@ -895,15 +896,17 @@ struct plugin_api { /* new stuff at the end, sort into place next time the API gets incompatible */ struct dirinfo (*dir_get_info)(DIR* parent, struct dirent *entry); + + /* load code api for overlay */ + void* (*lc_open)(const char *filename, unsigned char *buf, size_t buf_size); + void* (*lc_open_from_mem)(void* addr, size_t blob_size); + void* (*lc_get_header)(void *handle); + void (*lc_close)(void *handle); }; /* plugin header */ struct plugin_header { - unsigned long magic; - unsigned short target_id; - unsigned short api_version; - unsigned char *load_addr; - unsigned char *end_addr; + struct lc_header lc_hdr; /* must be the first */ enum plugin_status(*entry_point)(const void*); const struct plugin_api **api; }; @@ -916,15 +919,15 @@ extern unsigned char plugin_end_addr[]; const struct plugin_api *rb DATA_ATTR; \ const struct plugin_header __header \ __attribute__ ((section (".header")))= { \ - PLUGIN_MAGIC, TARGET_ID, PLUGIN_API_VERSION, \ - plugin_start_addr, plugin_end_addr, plugin__start, &rb }; + { PLUGIN_MAGIC, TARGET_ID, PLUGIN_API_VERSION, \ + plugin_start_addr, plugin_end_addr }, plugin__start, &rb }; #else /* PLATFORM_HOSTED */ #define PLUGIN_HEADER \ const struct plugin_api *rb DATA_ATTR; \ const struct plugin_header __header \ __attribute__((visibility("default"))) = { \ - PLUGIN_MAGIC, TARGET_ID, PLUGIN_API_VERSION, \ - NULL, NULL, plugin__start, &rb }; + { PLUGIN_MAGIC, TARGET_ID, PLUGIN_API_VERSION, NULL, NULL }, + plugin__start, &rb }; #endif /* CONFIG_PLATFORM */ #endif /* PLUGIN */ diff --git a/apps/plugins/lib/overlay.c b/apps/plugins/lib/overlay.c index 8a04cf8aa7..f64df29823 100644 --- a/apps/plugins/lib/overlay.c +++ b/apps/plugins/lib/overlay.c @@ -47,64 +47,56 @@ enum plugin_status run_overlay(const void* parameter, unsigned char *filename, unsigned char *name) { - int fd, readsize; size_t audiobuf_size; unsigned char *audiobuf; - static struct plugin_header header; - - fd = rb->open(filename, O_RDONLY); - if (fd < 0) - { - rb->splashf(2*HZ, "Can't open %s", filename); - return PLUGIN_ERROR; - } - readsize = rb->read(fd, &header, sizeof(header)); - rb->close(fd); - /* Close for now. Less code than doing it in all error checks. - * Would need to seek back anyway. */ - - if (readsize != sizeof(header)) - { - rb->splashf(2*HZ, "Reading %s overlay failed.", name); - return PLUGIN_ERROR; - } - if (header.magic != PLUGIN_MAGIC || header.target_id != TARGET_ID) - { - rb->splashf(2*HZ, "%s overlay: Incompatible model.", name); - return PLUGIN_ERROR; - } - if (header.api_version != PLUGIN_API_VERSION) - { - rb->splashf(2*HZ, "%s overlay: Incompatible version.", name); - return PLUGIN_ERROR; - } + void *handle; + struct plugin_header *p_hdr; + struct lc_header *hdr; audiobuf = rb->plugin_get_audio_buffer(&audiobuf_size); - if (header.load_addr < audiobuf || - header.end_addr > audiobuf + audiobuf_size) + if (!audiobuf) { - rb->splashf(2*HZ, "%s overlay doesn't fit into memory.", name); - return PLUGIN_ERROR; + rb->splash(2*HZ, "Can't optain memory"); + goto error; } - fd = rb->open(filename, O_RDONLY); - if (fd < 0) + handle = rb->lc_open(filename, audiobuf, audiobuf_size); + if (!handle) { rb->splashf(2*HZ, "Can't open %s", filename); - return PLUGIN_ERROR; + goto error; } - readsize = rb->read(fd, header.load_addr, header.end_addr - header.load_addr); - rb->close(fd); - if (readsize < 0) + p_hdr = rb->lc_get_header(handle); + if (!p_hdr) { - rb->splashf(2*HZ, "Reading %s overlay failed.", name); - return PLUGIN_ERROR; + rb->splash(2*HZ, "Can't get header"); + goto error_close; } - /* Zero out bss area */ - rb->memset(header.load_addr + readsize, 0, - header.end_addr - (header.load_addr + readsize)); + else + hdr = &p_hdr->lc_hdr; - *(header.api) = rb; - return header.entry_point(parameter); + if (hdr->magic != PLUGIN_MAGIC || hdr->target_id != TARGET_ID) + { + rb->splashf(2*HZ, "%s overlay: Incompatible model.", name); + goto error_close; + } + + + if (hdr->api_version > PLUGIN_API_VERSION + || hdr->api_version < PLUGIN_MIN_API_VERSION) + { + rb->splashf(2*HZ, "%s overlay: Incompatible version.", name); + goto error_close; + } + + rb->lc_close(handle); + + *(p_hdr->api) = rb; + return p_hdr->entry_point(parameter); + +error_close: + rb->lc_close(handle); +error: + return PLUGIN_ERROR; } diff --git a/firmware/export/load_code.h b/firmware/export/load_code.h index 6f5e5d0842..55ce601ee5 100644 --- a/firmware/export/load_code.h +++ b/firmware/export/load_code.h @@ -20,17 +20,21 @@ ****************************************************************************/ +#ifndef __LOAD_CODE_H__ +#define __LOAD_CODE_H__ + #include "config.h" #if (CONFIG_PLATFORM & PLATFORM_NATIVE) #include "system.h" -extern void *lc_open(const char *filename, char *buf, size_t buf_size); +extern void *lc_open(const char *filename, unsigned char *buf, size_t buf_size); /* header is always at the beginning of the blob, and handle actually points - * to the start of the blob */ + * to the start of the blob (the header is there) */ static inline void *lc_open_from_mem(void* addr, size_t blob_size) { (void)blob_size; + /* commit dcache and discard icache */ cpucache_invalidate(); return addr; } @@ -48,14 +52,27 @@ static inline void lc_close(void *handle) { (void)handle; } #else #define _lc_open_char char #endif -extern void *_lc_open(const _lc_open_char *filename, char *buf, size_t buf_size); +extern void *_lc_open(const _lc_open_char *filename, unsigned char *buf, size_t buf_size); extern void *_lc_get_header(void *handle); extern void _lc_close(void *handle); -extern void *lc_open(const char *filename, char *buf, size_t buf_size); -/* not possiible on hosted platforms */ +extern void *lc_open(const char *filename, unsigned char *buf, size_t buf_size); extern void *lc_open_from_mem(void *addr, size_t blob_size); extern void *lc_get_header(void *handle); extern void lc_close(void *handle); extern const char* lc_last_error(void); #endif + +/* this struct needs to be the first part of other headers + * (lc_open() casts the other header to this one to load to the correct + * address) + */ +struct lc_header { + unsigned long magic; + unsigned short target_id; + unsigned short api_version; + unsigned char *load_addr; + unsigned char *end_addr; +}; + +#endif /* __LOAD_CODE_H__ */ diff --git a/firmware/load_code.c b/firmware/load_code.c index 75bac8b2ac..5b5307e622 100644 --- a/firmware/load_code.c +++ b/firmware/load_code.c @@ -26,37 +26,77 @@ #include "load_code.h" #if (CONFIG_PLATFORM & PLATFORM_NATIVE) + /* load binary blob from disk to memory, returning a handle */ -void * lc_open(const char *filename, char *buf, size_t buf_size) +void * lc_open(const char *filename, unsigned char *buf, size_t buf_size) { int fd = open(filename, O_RDONLY); ssize_t read_size; + struct lc_header hdr; + unsigned char *buf_end = buf+buf_size; + off_t copy_size; if (fd < 0) { DEBUGF("Could not open file"); - return NULL; + goto error; } #if NUM_CORES > 1 /* Make sure COP cache is flushed and invalidated before loading */ { int my_core = switch_core(CURRENT_CORE ^ 1); - cpucache_invalidate(); + cpucache_commit_discard(); switch_core(my_core); } #endif - read_size = read(fd, buf, buf_size); - close(fd); - cpucache_invalidate(); + /* read the header to obtain the load address */ + read_size = read(fd, &hdr, sizeof(hdr)); if (read_size < 0) { DEBUGF("Could not read from file"); - return NULL; + goto error_fd; } - return buf; + + /* hdr.end_addr points to the end of the bss section, + * but there might be idata/icode behind that so the bytes to copy + * can be larger */ + copy_size = MAX(filesize(fd), hdr.end_addr - hdr.load_addr); + + if (hdr.load_addr < buf || (hdr.load_addr+copy_size) > buf_end) + { + DEBUGF("Binary doesn't fit into memory"); + goto error_fd; + } + + /* go back to beginning to load the whole thing (incl. header) */ + if (lseek(fd, 0, SEEK_SET) < 0) + { + DEBUGF("lseek failed"); + goto error_fd; + } + + /* the header has the addresses where the code is linked at */ + read_size = read(fd, hdr.load_addr, copy_size); + close(fd); + + if (read_size < 0) + { + DEBUGF("Could not read from file"); + goto error; + } + + /* commit dcache and discard icache */ + cpucache_commit_discard(); + /* return a pointer the header, reused by lc_get_header() */ + return hdr.load_addr; + +error_fd: + close(fd); +error: + return NULL; } #elif (CONFIG_PLATFORM & PLATFORM_HOSTED) @@ -85,12 +125,11 @@ static inline char *_dlerror(void) #include "rbpaths.h" #include "general.h" -void * _lc_open(const _lc_open_char *filename, char *buf, size_t buf_size) +void * _lc_open(const _lc_open_char *filename, unsigned char *buf, size_t buf_size) { (void)buf; (void)buf_size; - void* dl_handle = dlopen(filename, RTLD_NOW); - return dl_handle; + return dlopen(filename, RTLD_NOW); } void *lc_open_from_mem(void *addr, size_t blob_size) diff --git a/firmware/target/hosted/android/lc-android.c b/firmware/target/hosted/android/lc-android.c index 52ab08badb..434e901a56 100644 --- a/firmware/target/hosted/android/lc-android.c +++ b/firmware/target/hosted/android/lc-android.c @@ -23,7 +23,7 @@ #include "load_code.h" /* the load_code wrappers simply wrap, nothing to do */ -void *lc_open(const char *filename, char *buf, size_t buf_size) +void *lc_open(const char *filename, unsigned char *buf, size_t buf_size) { return _lc_open(filename, buf, buf_size); } diff --git a/uisimulator/common/io.c b/uisimulator/common/io.c index 56f1339fbc..3591905e32 100644 --- a/uisimulator/common/io.c +++ b/uisimulator/common/io.c @@ -526,7 +526,7 @@ int sim_fsync(int fd) #ifndef __PCTOOL__ -void *lc_open(const char *filename, char *buf, size_t buf_size) +void *lc_open(const char *filename, unsigned char *buf, size_t buf_size) { const char *sim_path = get_sim_pathname(filename); void *handle = _lc_open(UTF8_TO_OS(sim_path), buf, buf_size);