/* * Copyright (c) 1997-2015, Actions Semi Co., Inc. * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include #include #include #include #include #ifdef CONFIG_LOAD_IMAGE_FROM_FS #include #endif /* LOAD_IMAGE_FROM_FS */ #include "dsp_image.h" #ifndef CONFIG_LOAD_IMAGE_FROM_FS static int load_scntable(const void *image, unsigned int offset, bool is_code) { const struct IMG_scnhdr *scnhdr = (const struct IMG_scnhdr *)((uint32_t)image + offset); if (scnhdr->size == 0) return -ENODATA; for (; scnhdr->size > 0; ) { uint32_t cpu_addr = dsp_to_mcu_address(scnhdr->addr, is_code); if (cpu_addr == UINT32_MAX) { printk("invalid address 0x%08x\n", scnhdr->addr); return -EFAULT; } #if 0 printk("load: offset=0x%08x, size=0x%08x, dsp_addr=0x%08x, cpu_addr=0x%08x\n", (unsigned int)(scnhdr->data - (const uint8_t *)image), scnhdr->size, scnhdr->addr, cpu_addr); #endif dsp_soc_release_addr(cpu_addr); memcpy((void*)cpu_addr, scnhdr->data, scnhdr->size); dsp_soc_request_addr(cpu_addr); scnhdr = (struct IMG_scnhdr*)&scnhdr->data[scnhdr->size]; } return 0; } int load_dsp_image_bank(const void *image, size_t size, unsigned int bank_no) { const struct IMG_filehdr *filehdr = image; if (bank_no >= NUM_BANKS) { printk("invalid bank number %u\n", bank_no); return -EINVAL; } assert(size > filehdr->bank_scnptr[bank_no][0]); assert(size > filehdr->bank_scnptr[bank_no][1]); if (!filehdr->bank_scnptr[bank_no][0] && !filehdr->bank_scnptr[bank_no][1]) { printk("bank[%u] empty\n", bank_no); return -ENODATA; } if (filehdr->bank_scnptr[bank_no][0]) { if (load_scntable(image, filehdr->bank_scnptr[bank_no][0], true)) { printk("failed to load bank[%u] code\n", bank_no); return -EINVAL; } } if (filehdr->bank_scnptr[bank_no][1]) { if (load_scntable(image, filehdr->bank_scnptr[bank_no][1], false)) { printk("failed to load bank[%u] data\n", bank_no); return -EINVAL; } } return 0; } int load_dsp_image(const void *image, size_t size, uint32_t *entry_point) { const struct IMG_filehdr *filehdr = image; /* FIXME: use sys_get_le32 to handle unaligned 32bit access insead ? */ if ((uint32_t)image & 0x3) { printk("image load address %p should be aligned to 4, " "could use __attribute__((__aligned__(x)))\n", image); return -EFAULT; } assert(size > sizeof(*filehdr)); assert(size > filehdr->code_scnptr); assert(size > filehdr->code_scnptr); if (filehdr->magic != IMAGE_MAGIC('y', 'q', 'h', 'x')) { printk("invalid dsp magic 0x%08x\n", filehdr->magic); return -EINVAL; } if (filehdr->code_scnptr) { if (load_scntable(image, filehdr->code_scnptr, true)) { printk("failed to load code\n"); return -EINVAL; } } if (filehdr->data_scnptr) { if (load_scntable(image, filehdr->data_scnptr, false)) { printk("failed to load data\n"); return -EINVAL; } } if (entry_point) *entry_point = filehdr->entry_point; return 0; } #endif #ifdef CONFIG_LOAD_IMAGE_FROM_FS static int load_scntable_from_file(struct fs_file_t *file, long offset, bool is_code) { if (offset <= 0) return 0; if (fs_seek(file, offset, FS_SEEK_SET)) { printk("seek_file failed\n"); return -EIO; } do { struct IMG_scnhdr scnhdr; ssize_t ssize = fs_read(file, &scnhdr, sizeof(scnhdr)); if (ssize < sizeof(scnhdr.size)) { printk("invalid image\n"); return -EINVAL; } if (scnhdr.size == 0) { //printk("scnhdr.size %d \n",scnhdr.size); break; } uint32_t cpu_addr = dsp_to_mcu_address(scnhdr.addr, is_code); if (cpu_addr == UINT32_MAX) { printk("invalid address 0x%08x\n", scnhdr.addr); return -EFAULT; } printk("load: offset=0x%08x, size=0x%08x, dsp_addr=0x%08x, cpu_addr=0x%08x \n", (unsigned int)fs_tell(file), scnhdr.size, scnhdr.addr, cpu_addr); dsp_soc_release_addr(cpu_addr); ssize = fs_read(file, (void *)cpu_addr, scnhdr.size); dsp_soc_request_addr(cpu_addr); if (ssize < scnhdr.size) { printk("ssize %d scnhdr.size %d \n",ssize,scnhdr.size); return -EIO; } } while (true); return 0; } int load_dsp_image_bank_from_file(void *filp, unsigned int bank_no) { struct fs_file_t *file = filp; struct IMG_filehdr filehdr; ssize_t ssize; fs_seek(file, 0, FS_SEEK_SET); ssize = fs_read(file, &filehdr, sizeof(filehdr)); if (ssize < sizeof(filehdr)) { printk("invalid image\n"); return -EINVAL; } if (!filehdr.bank_scnptr[bank_no][0] && !filehdr.bank_scnptr[bank_no][1]) { printk("bank[%u] empty\n", bank_no); return -ENODATA; } if (filehdr.bank_scnptr[bank_no][0]) { if (load_scntable_from_file(file, filehdr.bank_scnptr[bank_no][0], true)) { printk("failed to load bank[%u] code\n", bank_no); return -EINVAL; } } if (filehdr.bank_scnptr[bank_no][1]) { if (load_scntable_from_file(file, filehdr.bank_scnptr[bank_no][1], false)) { printk("failed to load bank[%u] data\n", bank_no); return -EINVAL; } } return 0; } int load_dsp_image_from_file(void *filp, uint32_t *entry_point) { struct fs_file_t *file = filp; struct IMG_filehdr filehdr; ssize_t ssize; int ret = 0; ret = fs_seek(file, 0, FS_SEEK_SET); ssize = fs_read(file, &filehdr, sizeof(filehdr)); if (ssize < sizeof(filehdr)) { printk("invalid image\n"); return -EINVAL; } if (filehdr.magic != IMAGE_MAGIC('y', 'q', 'h', 'x')) { printk("dsp magic error\n"); return -EINVAL; } if (filehdr.code_scnptr) { if (load_scntable_from_file(file, filehdr.code_scnptr, true)) { printk("failed to load code\n"); return -EINVAL; } } if (filehdr.data_scnptr) { if (load_scntable_from_file(file, filehdr.data_scnptr, false)) { printk("failed to load data\n"); return -EINVAL; } } if (entry_point) *entry_point = filehdr.entry_point; return 0; } #endif /* LOAD_IMAGE_FROM_FS */