Ejemplo n.º 1
0
int fiasco_write_to_file(struct fiasco * fiasco, const char * file) {

    int fd = -1;
    int i;
    int device_count;
    uint32_t size;
    uint32_t length;
    uint16_t hash;
    uint8_t length8;
    char ** device_hwrevs_bufs;
    const char * str;
    const char * type;
    struct image_list * image_list;
    struct image * image;
    unsigned char buf[4096];

    if ( ! fiasco )
        return -1;

    printf("Generating Fiasco image %s...\n", file);

    if ( ! fiasco->first )
        FIASCO_WRITE_ERROR(file, fd, "Nothing to write");

    if ( fiasco->name && strlen(fiasco->name)+1 > UINT8_MAX )
        FIASCO_WRITE_ERROR(file, fd, "Fiasco name string is too long");

    if ( fiasco->swver && strlen(fiasco->swver)+1 > UINT8_MAX )
        FIASCO_WRITE_ERROR(file, fd, "SW version string is too long");

    if ( ! simulate ) {
        fd = open(file, O_RDWR|O_CREAT|O_TRUNC, 0644);
        if ( fd < 0 ) {
            ERROR_INFO("Cannot create file");
            return -1;
        }
    }

    printf("Writing Fiasco header...\n");

    WRITE_OR_FAIL(file, fd, "\xb4", 1); /* signature */

    if ( fiasco->name[0] )
        str = fiasco->name;
    else
        str = "OSSO UART+USB";

    length = 4 + strlen(str) + 3;
    if ( fiasco->swver[0] )
        length += strlen(fiasco->swver) + 3;
    length = htonl(length);
    WRITE_OR_FAIL(file, fd, &length, 4); /* FW header length */

    if ( fiasco->swver[0] )
        length = htonl(2);
    else
        length = htonl(1);
    WRITE_OR_FAIL(file, fd, &length, 4); /* FW header blocks count */

    /* Fiasco name */
    length8 = strlen(str)+1;
    WRITE_OR_FAIL(file, fd, "\xe8", 1);
    WRITE_OR_FAIL(file, fd, &length8, 1);
    WRITE_OR_FAIL(file, fd, str, length8);

    /* SW version */
    if ( fiasco->swver[0] ) {
        printf("Writing SW version: %s\n", fiasco->swver);
        length8 = strlen(fiasco->swver)+1;
        WRITE_OR_FAIL(file, fd, "\x31", 1);
        WRITE_OR_FAIL(file, fd, &length8, 1);
        WRITE_OR_FAIL(file, fd, fiasco->swver, length8);
    };

    printf("\n");

    image_list = fiasco->first;

    while ( image_list ) {

        image = image_list->image;

        if ( ! image )
            FIASCO_WRITE_ERROR(file, fd, "Empty image");

        printf("Writing image...\n");
        image_print_info(image);

        type = image_type_to_string(image->type);

        device_hwrevs_bufs = device_list_alloc_to_bufs(image->devices);

        device_count = 0;
        if ( device_hwrevs_bufs && device_hwrevs_bufs[0] )
            for ( ; device_hwrevs_bufs[device_count]; ++device_count );

        if ( ! type )
            FIASCO_WRITE_ERROR(file, fd, "Unknown image type");

        if ( image->version && strlen(image->version) > UINT8_MAX )
            FIASCO_WRITE_ERROR(file, fd, "Image version string is too long");

        if ( image->layout && strlen(image->layout) > UINT8_MAX )
            FIASCO_WRITE_ERROR(file, fd, "Image layout is too long");

        printf("Writing image header...\n");

        /* signature */
        WRITE_OR_FAIL(file, fd, "T", 1);

        /* number of subsections */
        length8 = device_count+1;
        if ( image->version )
            ++length8;
        if ( image->layout )
            ++length8;
        WRITE_OR_FAIL(file, fd, &length8, 1);

        /* unknown */
        WRITE_OR_FAIL(file, fd, "\x2e\x19\x01\x01\x00", 5);

        /* checksum */
        hash = htons(image->hash);
        WRITE_OR_FAIL(file, fd, &hash, 2);

        /* image type name */
        memset(buf, 0, 12);
        strncpy((char *)buf, type, 12);
        WRITE_OR_FAIL(file, fd, buf, 12);

        /* image size */
        size = htonl(image->size);
        WRITE_OR_FAIL(file, fd, &size, 4);

        /* unknown */
        WRITE_OR_FAIL(file, fd, "\x00\x00\x00\x00", 4);

        /* append version subsection */
        if ( image->version ) {
            WRITE_OR_FAIL(file, fd, "1", 1); /* 1 - version */
            length8 = strlen(image->version)+1;
            WRITE_OR_FAIL(file, fd, &length8, 1);
            WRITE_OR_FAIL(file, fd, image->version, length8);
        }

        /* append device & hwrevs subsection */
        for ( i = 0; i < device_count; ++i ) {
            WRITE_OR_FAIL(file, fd, "2", 1); /* 2 - device & hwrevs */
            WRITE_OR_FAIL(file, fd, &device_hwrevs_bufs[i][0], 1);
            WRITE_OR_FAIL(file, fd, device_hwrevs_bufs[i]+1, ((uint8_t *)(device_hwrevs_bufs[i]))[0]);
        }
        free(device_hwrevs_bufs);

        /* append layout subsection */
        if ( image->layout ) {
            length8 = strlen(image->layout);
            WRITE_OR_FAIL(file, fd, "3", 1); /* 3 - layout */
            WRITE_OR_FAIL(file, fd, &length8, 1);
            WRITE_OR_FAIL(file, fd, image->layout, length8);
        }

        /* dummy byte - end of all subsections */
        WRITE_OR_FAIL(file, fd, "\x00", 1);

        printf("Writing image data...\n");

        image_seek(image, 0);
        while ( 1 ) {
            size = image_read(image, buf, sizeof(buf));
            if ( size == 0 )
                break;
            WRITE_OR_FAIL(file, fd, buf, size);
        }

        image_list = image_list->next;

        if ( image_list )
            printf("\n");

    }

    close(fd);
    printf("\nDone\n\n");
    return 0;

}
Ejemplo n.º 2
0
int fiasco_unpack(struct fiasco * fiasco, const char * dir) {

    int fd = -1;
    char * name = NULL;
    char * layout_name = NULL;
    struct image * image;
    struct image_list * image_list;
    uint32_t size;
    char cwd[256];
    unsigned char buf[4096];

    if ( dir ) {

        memset(cwd, 0, sizeof(cwd));

        if ( ! getcwd(cwd, sizeof(cwd)) ) {
            ERROR_INFO("Cannot store current directory");
            return -1;
        }

        if ( chdir(dir) < 0 ) {
            ERROR_INFO("Cannot change current directory to %s", dir);
            return -1;
        }

    }

    fiasco_print_info(fiasco);

    image_list = fiasco->first;

    while ( image_list ) {

        image = image_list->image;

        name = image_name_alloc_from_values(image);
        if ( ! name )
            return -1;

        printf("\n");
        printf("Unpacking image...\n");
        image_print_info(image);

        if ( image->layout ) {

            layout_name = calloc(1, strlen(name) + strlen(".layout") + 1);
            if ( ! layout_name )
                ALLOC_ERROR_RETURN(-1);

            sprintf(layout_name, "%s.layout", name);

            printf("    Layout file: %s\n", layout_name);

        }

        printf("    Output file: %s\n", name);

        if ( ! simulate ) {
            fd = open(name, O_RDWR|O_CREAT|O_TRUNC, 0644);
            if ( fd < 0 ) {
                ERROR_INFO("Cannot create output file %s", name);
                return -1;
            }
        }

        free(name);

        image_seek(image, 0);
        while ( 1 ) {
            size = image_read(image, buf, sizeof(buf));
            if ( size == 0 )
                break;
            WRITE_OR_FAIL(name, fd, buf, size);
        }

        close(fd);

        if ( image->layout ) {

            if ( ! simulate ) {
                fd = open(layout_name, O_RDWR|O_CREAT|O_TRUNC, 0644);
                if ( fd < 0 ) {
                    ERROR_INFO("Cannot create layout file %s", layout_name);
                    return -1;
                }
            }

            free(layout_name);

            WRITE_OR_FAIL(layout_name, fd, image->layout, (int)strlen(image->layout));

            close(fd);

        }

        image_list = image_list->next;

    }

    if ( dir ) {
        if ( chdir(cwd) < 0 ) {
            ERROR_INFO("Cannot change current directory back to %s", cwd);
            return -1;
        }
    }

    printf("\nDone\n\n");
    return 0;

}
Ejemplo n.º 3
0
/*
 *
 * The implementation assumes that the loadable segments are present
 * in the PHT sorted by their offsets, so that only forward seeks would
 * be necessary.
 */
int load_segments(struct elf_module *module, Elf_Ehdr *elf_hdr) {
	int i;
	int res = 0;
	char *pht = NULL;
	char *sht = NULL;
	Elf32_Phdr *cr_pht;
	Elf32_Shdr *cr_sht;

	Elf32_Addr min_addr  = 0x00000000; // Min. ELF vaddr
	Elf32_Addr max_addr  = 0x00000000; // Max. ELF vaddr
	Elf32_Word max_align = sizeof(void*); // Min. align of posix_memalign()
	Elf32_Addr min_alloc, max_alloc;   // Min. and max. aligned allocables

	Elf32_Addr dyn_addr = 0x00000000;

	// Get to the PHT
	image_seek(elf_hdr->e_phoff, module);

	// Load the PHT
	pht = malloc(elf_hdr->e_phnum * elf_hdr->e_phentsize);
	if (!pht)
		return -1;

	image_read(pht, elf_hdr->e_phnum * elf_hdr->e_phentsize, module);

	// Compute the memory needings of the module
	for (i=0; i < elf_hdr->e_phnum; i++) {
		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);

		switch (cr_pht->p_type) {
		case PT_LOAD:
			if (i == 0) {
				min_addr = cr_pht->p_vaddr;
			} else {
				min_addr = MIN(min_addr, cr_pht->p_vaddr);
			}

			max_addr = MAX(max_addr, cr_pht->p_vaddr + cr_pht->p_memsz);
			max_align = MAX(max_align, cr_pht->p_align);
			break;
		case PT_DYNAMIC:
			dyn_addr = cr_pht->p_vaddr;
			break;
		default:
			// Unsupported - ignore
			break;
		}
	}

	if (max_addr - min_addr == 0) {
		// No loadable segments
		DBG_PRINT("No loadable segments found\n");
		goto out;
	}

	if (dyn_addr == 0) {
		DBG_PRINT("No dynamic information segment found\n");
		goto out;
	}

	// The minimum address that should be allocated
	min_alloc = min_addr - (min_addr % max_align);

	// The maximum address that should be allocated
	max_alloc = max_addr - (max_addr % max_align);
	if (max_addr % max_align > 0)
		max_alloc += max_align;


	if (elf_malloc(&module->module_addr,
			max_align,
			max_alloc-min_alloc) != 0) {

		DBG_PRINT("Could not allocate segments\n");
		goto out;
	}

	module->base_addr = (Elf32_Addr)(module->module_addr) - min_alloc;
	module->module_size = max_alloc - min_alloc;

	// Zero-initialize the memory
	memset(module->module_addr, 0, module->module_size);

	for (i = 0; i < elf_hdr->e_phnum; i++) {
		cr_pht = (Elf32_Phdr*)(pht + i * elf_hdr->e_phentsize);

		if (cr_pht->p_type == PT_LOAD) {
			// Copy the segment at its destination
			if (cr_pht->p_offset < module->u.l._cr_offset) {
				// The segment contains data before the current offset
				// It can be discarded without worry - it would contain only
				// headers
				Elf32_Off aux_off = module->u.l._cr_offset - cr_pht->p_offset;

				if (image_read((char *)module_get_absolute(cr_pht->p_vaddr, module) + aux_off,
					       cr_pht->p_filesz - aux_off, module) < 0) {
					res = -1;
					goto out;
				}
			} else {
				if (image_seek(cr_pht->p_offset, module) < 0) {
					res = -1;
					goto out;
				}

				if (image_read(module_get_absolute(cr_pht->p_vaddr, module),
						cr_pht->p_filesz, module) < 0) {
					res = -1;
					goto out;
				}
			}

			/*
			DBG_PRINT("Loadable segment of size 0x%08x copied from vaddr 0x%08x at 0x%08x\n",
					cr_pht->p_filesz,
					cr_pht->p_vaddr,
					(Elf32_Addr)module_get_absolute(cr_pht->p_vaddr, module));
			*/
		}
	}

	// Get to the SHT
	image_seek(elf_hdr->e_shoff, module);

	// Load the SHT
	sht = malloc(elf_hdr->e_shnum * elf_hdr->e_shentsize);
	if (!sht) {
		res = -1;
		goto out;
	}

	image_read(sht, elf_hdr->e_shnum * elf_hdr->e_shentsize, module);

	// Setup the symtable size
	for (i = 0; i < elf_hdr->e_shnum; i++) {
		cr_sht = (Elf32_Shdr*)(sht + i * elf_hdr->e_shentsize);

		if (cr_sht->sh_type == SHT_DYNSYM) {
			module->symtable_size = cr_sht->sh_size;
			break;
		}
	}

	free(sht);

	// Setup dynamic segment location
	module->dyn_table = module_get_absolute(dyn_addr, module);

	/*
	DBG_PRINT("Base address: 0x%08x, aligned at 0x%08x\n", module->base_addr,
			max_align);
	DBG_PRINT("Module size: 0x%08x\n", module->module_size);
	*/

out:
	// Free up allocated memory
	if (pht != NULL)
		free(pht);

	return res;
}