コード例 #1
0
ファイル: recovery.c プロジェクト: jaehyek/lk
int get_recovery_message(struct recovery_message *out)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();

	ptable = flash_get_ptable();

	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}
	ptn = ptable_find(ptable, "misc");

	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No misc partition found\n");
		return -1;
	}

	offset += (pagesize * MISC_COMMAND_PAGE);
	if (flash_read(ptn, offset, (void *) buf, pagesize)) {
		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
		return -1;
	}
	memcpy(out, buf, sizeof(*out));
	return 0;
}
コード例 #2
0
ファイル: recovery.c プロジェクト: jaehyek/lk
static int set_ssd_radio_update (char *name)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned int ssd_cookie[2] = {0x53534443, 0x4F4F4B49};
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;

	ptable = flash_get_ptable();
	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}

	n = (sizeof(ssd_cookie) + pagemask) & (~pagemask);

	ptn = ptable_find(ptable, name);
	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
		return -1;
	}

	if (flash_write(ptn, 0, ssd_cookie, n)) {
		dprintf(CRITICAL, "ERROR: flash write fail!\n");
		return -1;
	}

	dprintf(INFO, "FOTA partition written successfully!");
	return 0;
}
コード例 #3
0
ファイル: recovery.c プロジェクト: jaehyek/lk
int read_update_header_for_bootloader(struct update_header *header)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();

	ptable = flash_get_ptable();
	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}
	ptn = ptable_find(ptable, "cache");

	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}
	if (flash_read(ptn, offset, buf, pagesize)) {
		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
		return -1;
	}
	memcpy(header, buf, sizeof(*header));

	if (strncmp((char *) header->MAGIC, UPDATE_MAGIC, UPDATE_MAGIC_SIZE))
	{
		return -1;
	}
	return 0;
}
コード例 #4
0
int update_firmware_emmc_image (struct update_header *header, char *name)
{
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;
	unsigned long long ptn = 0;
	unsigned ret;

	ptn = emmc_ptn_offset("cache");

	if (ptn == 0) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}

	offset += header->image_offset;
	n = (header->image_length + pagemask) & (~pagemask);


	if (emmc_read(ptn, n+60, SCRATCH_ADDR))
	{
		dprintf(CRITICAL, "ERROR: Cannot read bootloader image\n");
		return -1;
	}

	memcpy(SCRATCH_ADDR,SCRATCH_ADDR+0x03c, n); 

	if (!strcmp(name, "bootloader")) 
		FwdnUpdateBootSDFirmware(n);

	dprintf(INFO, "Partition writen successfully!");
	return 0;
}
コード例 #5
0
ファイル: sdhc-spi.c プロジェクト: Kefir0192/uos-embedded
//
// Запись одной страницы данных (в режиме мультиблочной записи).
// data - указатель на буфер с данными
// size - размер буфера
//
static int
do_write_one_page(sdhc_spi_t *m, void *data, unsigned size)
{
    int res;
    
    // Дожидаемся освобождения линии
    res = wait_line_free(m);
    if (res != FLASH_ERR_OK)
        return res;
    
    // Отправляем маркер начала данных
    m->msg.word_count = 1;
    m->databuf[0] = MULTI_START_BLOCK_TOKEN;
    if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK)
        return FLASH_ERR_IO;

    // Выдаём требуемый размер данных
    m->msg.rx_data = 0;
    m->msg.tx_data = data;
    m->msg.word_count = size;
    if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK) {
        return FLASH_ERR_IO;
    }
    
    // Обмен с картой всегда происходит блоками по 512 байт.
    // Поэтому оставшиеся байты всё равно необходимо передать. Для этого
    // используем вспомогательный буфер databuf
    size = flash_page_size((flashif_t*)m) - size;
    m->msg.tx_data = m->databuf;
    if (size > 0) memset(m->databuf, 0xFF, sizeof(m->databuf));
    while (size > 0) {
        m->msg.word_count = (sizeof(m->databuf) < size) ?
            sizeof(m->databuf) : size;
        if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK)
            return FLASH_ERR_IO;
        size -= m->msg.word_count;
    };
    
    // Дожидаемся ответа со статусом завершения операции
    m->msg.rx_data = m->databuf;
    m->msg.word_count = 1;
    uint8_t token;
    do {
        m->databuf[0] = 0xFF;
        if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK) 
            return FLASH_ERR_IO;
        token = m->databuf[0] & DATA_RESPONSE_MASK;
    } while (token != DATA_ACCEPTED && token != DATA_WRITE_ERROR);
    
    if (token == DATA_WRITE_ERROR)
        return FLASH_ERR_IO;
        
    return FLASH_ERR_OK;
}
コード例 #6
0
ファイル: recovery.c プロジェクト: jaehyek/lk
int update_firmware_image (struct update_header *header, char *name)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;
	void *scratch_addr = target_get_scratch_address();

	ptable = flash_get_ptable();
	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}

	ptn = ptable_find(ptable, "cache");
	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}

	offset += header->image_offset;
	n = (header->image_length + pagemask) & (~pagemask);

	if (flash_read(ptn, offset, scratch_addr, n)) {
		dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
		return -1;
	}

	ptn = ptable_find(ptable, name);
	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
		return -1;
	}

	if (flash_write(ptn, 0, scratch_addr, n)) {
		dprintf(CRITICAL, "ERROR: flash write fail!\n");
		return -1;
	}

	dprintf(INFO, "Partition writen successfully!");
	return 0;
}
コード例 #7
0
int update_firmware_image_v8(struct update_header *header, char *name)
{
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;
	unsigned long long ptn = 0;
	unsigned ret;

	ptn = flash_ptn_offset("cache");
	if (ptn == 0) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}

	offset += header->image_offset;
	n = (header->image_length + pagemask) & (~pagemask);

	if (flash_read_tnftl_v8(ptn, n+60, SCRATCH_ADDR))
	{
		dprintf(CRITICAL, "ERROR: Cannot read bootloader image\n");
		return -1;
	}

	memcpy(SCRATCH_ADDR,SCRATCH_ADDR+0x03c, n); 

	if (!strcmp(name, "bootloader")) 
	{
	 	dprintf(ALWAYS, "\n[NAND] Bootloader Update Start !!! \n");
	 	ret = flash_write_tnftl_v8( name, 0, n , SCRATCH_ADDR);
		if( ret != 0 )	
		{
			dprintf(ALWAYS, "\n[NAND] Bootloader Update Fail [ret:0x%08X]!!! \n", ret);		
			return ret;
		}
		else	
			dprintf(ALWAYS, "\n[NAND] Bootloader Update Success !!! \n");

	}
	dprintf(INFO, "Partition writen successfully!");
	return 0;
}
コード例 #8
0
static int read_from_flash(struct ptentry* ptn, int offset, int size, void *dest)
{
	void *buffer = NULL;
	unsigned page_size = flash_page_size();
	unsigned page_mask = page_size - 1;
	int read_size = (size + page_mask) & (~page_mask);

	buffer = malloc(read_size);
	if(!buffer){
		dprintf(CRITICAL, "ERROR : Malloc failed for read_from_flash \n");
		return -1;
	}
	if(flash_read(ptn, offset, buffer, read_size)){
		dprintf(CRITICAL, "ERROR : Flash read failed \n");
		return -1;
	}
	memcpy(dest, buffer, size);
	free(buffer);
	return 0;
}
コード例 #9
0
ファイル: sdhc-spi.c プロジェクト: Kefir0192/uos-embedded
//
// Чтение одной страницы данных (в режиме мультиблочного чтения).
// data - указатель на буфер, в который следует положить принятые данные
// size - размер буфера
// existing_data - если не 0, то содержит указатель на уже принятую 
// часть данных (она лежит в буфере databuf).
//
static int
do_read_one_page(sdhc_spi_t *m, void *data, unsigned size, uint8_t *existing_data)
{
    int offset = 0;

    // Перенос уже принятой части данных в буфер data
    if (existing_data) {
        offset = existing_data - m->databuf + m->msg.word_count;
        memcpy(data, existing_data, offset);
        data = (uint8_t *)data + offset;
    }
    // Приём оставшихся данных с учётом их длины
    m->msg.rx_data = data;
    m->msg.tx_data = data;
    m->msg.word_count = size - offset;
    memset(data, 0xFF, m->msg.word_count);
    if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK)
        return FLASH_ERR_IO;
    
    // Обмен с картой всегда происходит блоками по 512 байт.
    // Даже оставшиеся данные не нужны (size < 512), всё равно
    // их нужно дочитать из SPI - в вспомогательный буфер databuf.
    m->msg.rx_data = 0;
    m->msg.tx_data = m->databuf;
    size = flash_page_size((flashif_t*)m) - size + 3;
    
    memset(m->databuf, 0xFF, sizeof(m->databuf));
    do {
        m->msg.word_count = (sizeof(m->databuf) < size) ?
            sizeof(m->databuf) : size;
        if (spim_trx(m->spi, &m->msg) != SPI_ERR_OK)
            return FLASH_ERR_IO;
        size -= m->msg.word_count;
    } while (size > 0);
    
    m->msg.rx_data = m->databuf;
        
    return FLASH_ERR_OK;
}
コード例 #10
0
ファイル: recovery.c プロジェクト: jaehyek/lk
int set_recovery_message(const struct recovery_message *in)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned n = 0;
	void *scratch_addr = target_get_scratch_address();

	ptable = flash_get_ptable();

	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}
	ptn = ptable_find(ptable, "misc");

	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No misc partition found\n");
		return -1;
	}

	n = pagesize * (MISC_COMMAND_PAGE + 1);

	if (flash_read(ptn, offset, scratch_addr, n)) {
		dprintf(CRITICAL, "ERROR: Cannot read recovery_header\n");
		return -1;
	}

	offset += (pagesize * MISC_COMMAND_PAGE);
	offset += (unsigned) scratch_addr;
	memcpy((void *) offset, in, sizeof(*in));
	if (flash_write(ptn, 0, scratch_addr, n)) {
		dprintf(CRITICAL, "ERROR: flash write fail!\n");
		return -1;
	}
	return 0;
}
コード例 #11
0
ファイル: recovery.c プロジェクト: jaehyek/lk
int write_misc(unsigned page_offset, void *buf, unsigned size)
{
	const char *ptn_name = "misc";
	void *scratch_addr = target_get_scratch_address();
	unsigned offset;
	unsigned aligned_size;

	if (size == 0 || buf == NULL || scratch_addr == NULL)
		return -1;

	if (target_is_emmc_boot())
	{
		int index;
		unsigned long long ptn;
		unsigned long long ptn_size;

		index = partition_get_index(ptn_name);
		if (index == INVALID_PTN)
		{
			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
			return -1;
		}

		ptn = partition_get_offset(index);
		ptn_size = partition_get_size(index);

		offset = page_offset * BLOCK_SIZE;
		aligned_size = ROUND_TO_PAGE(size, (unsigned)BLOCK_SIZE - 1);
		if (ptn_size < offset + aligned_size)
		{
			dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
					ptn_name);
			return -1;
		}

		if (scratch_addr != buf)
			memcpy(scratch_addr, buf, size);
		if (mmc_write(ptn + offset, aligned_size, (unsigned int *)scratch_addr))
		{
			dprintf(CRITICAL, "Writing MMC failed\n");
			return -1;
		}
	}
	else
	{
		struct ptentry *ptn;
		struct ptable *ptable;
		unsigned pagesize = flash_page_size();

		ptable = flash_get_ptable();
		if (ptable == NULL)
		{
			dprintf(CRITICAL, "Partition table not found\n");
			return -1;
		}

		ptn = ptable_find(ptable, ptn_name);
		if (ptn == NULL)
		{
			dprintf(CRITICAL, "No '%s' partition found\n", ptn_name);
			return -1;
		}

		offset = page_offset * pagesize;
		aligned_size = ROUND_TO_PAGE(size, pagesize - 1);
		if (ptn->length < offset + aligned_size)
		{
			dprintf(CRITICAL, "Write request out of '%s' boundaries\n",
					ptn_name);
			return -1;
		}

		if (scratch_addr != buf)
			memcpy(scratch_addr, buf, size);
		if (flash_write(ptn, offset, scratch_addr, aligned_size)) {
			dprintf(CRITICAL, "Writing flash failed\n");
			return -1;
		}
	}

	return 0;
}
コード例 #12
0
ファイル: sdhc-spi.c プロジェクト: Kefir0192/uos-embedded
//
// Интерфейсная функция записи данных.
// size может быть больше, чем размер страницы, и функция должна это
// учитывать.
//
static int 
sd_write(flashif_t *flash, unsigned page_num, 
    void *data, unsigned size)
{
    int res = FLASH_ERR_OK;
    sdhc_spi_t *m = (sdhc_spi_t *) flash;
    int exit = 0;
    uint8_t *cur_ptr = data;
    unsigned cur_size;

    mutex_lock(&flash->lock);

    do {
        switch (m->state) {
        case SDHC_STATE_MULTIREAD:
            // Карта сейчас в режиме многоблочного чтения, переводим
            // её сначала в нормальный режим
            res = stop_multiple_read(m);
            if (res != FLASH_ERR_OK) {
                exit = 1;
                break;
            }
            m->state = SDHC_STATE_IDLE;
            // Intentionally no break
            
        case SDHC_STATE_IDLE:
            // Инициируем режим многоблочной записи
            res = init_multiple_op(m, page_num, OP_WRITE, 0);
            if (res != FLASH_ERR_OK) {
                exit = 1;
                break;
            }
            m->state = SDHC_STATE_MULTIWRITE;
            m->next_page = page_num;
            // Intentionally no break
            
        case SDHC_STATE_MULTIWRITE:
            if (page_num == m->next_page) {
                // Карта в режиме многоблочной записи и требуемый
                // номер страницы является последовательным по отношению
                // к предыдущему - выполняем передачу очередного блока.
                // Дожидаемся начала блока.
                do {
                    // Выполняем запись одной страницы
                    cur_size = (size <= flash_page_size(flash)) ? 
                        size : flash_page_size(flash);
                    res = do_write_one_page(m, cur_ptr, cur_size);
                    if (res != FLASH_ERR_OK)
                        break;
                    m->next_page++;
                    cur_ptr += cur_size;
                    size -= cur_size;
                } while (size > 0);
                exit = 1;
            } else {
                // Карта в нужном режиме, но адрес не последовательный.
                // Останавливаем режим многоблочной записи, чтобы
                // потом заново его инициировать, но уже с нужным
                // номером страницы.
                res = stop_multiple_write(m);
                if (res != FLASH_ERR_OK) {
                    exit = 1;
                    break;
                }
                m->state = SDHC_STATE_IDLE;
            }
        break;
        }
    } while (!exit);

    mutex_unlock(&flash->lock);
    return res;

}
コード例 #13
0
int update_firmware_image (struct update_header *header, char *name)
{
	struct ptentry *ptn;
	struct ptable *ptable;
	unsigned offset = 0;
	unsigned pagesize = flash_page_size();
	unsigned pagemask = pagesize -1;
	unsigned n = 0;

	ptable = flash_get_ptable();
	if (ptable == NULL) {
		dprintf(CRITICAL, "ERROR: Partition table not found\n");
		return -1;
	}

	ptn = ptable_find(ptable, "cache");
	if (ptn == NULL) {
		dprintf(CRITICAL, "ERROR: No cache partition found\n");
		return -1;
	}

	offset += header->image_offset;
	n = (header->image_length + pagemask) & (~pagemask);

	if (flash_read(ptn, offset, SCRATCH_ADDR, n)) {
		dprintf(CRITICAL, "ERROR: Cannot read radio image\n");
		return -1;
	}

	if (!strcmp(name, "radio")) {
		ptn = ptable_find(ptable, name);
		if (ptn == NULL) {
			dprintf(CRITICAL, "ERROR: No %s partition found\n", name);
			return -1;
		}

		if (flash_write(ptn, 0, SCRATCH_ADDR, n)) {
			dprintf(CRITICAL, "ERROR: flash write fail!\n");
			return -1;
		}
	} else if (!strcmp(name, "bootloader")) {
#ifdef PLATFORM_TCC
		struct ptentry ptn = {
			.name = "bootloader",
		};

		flash_write(&ptn, 0, SCRATCH_ADDR, n);
#endif
	}


	dprintf(INFO, "Partition writen successfully!");
	return 0;
}

/* Bootloader / Recovery Flow
 *
 * On every boot, the bootloader will read the recovery_message
 * from flash and check the command field.  The bootloader should
 * deal with the command field not having a 0 terminator correctly
 * (so as to not crash if the block is invalid or corrupt).
 *
 * The bootloader will have to publish the partition that contains
 * the recovery_message to the linux kernel so it can update it.
 *
 * if command == "boot-recovery" -> boot recovery.img
 * else if command == "update-radio" -> update radio image (below)
 * else -> boot boot.img (normal boot)
 *
 * Radio Update Flow
 * 1. the bootloader will attempt to load and validate the header
 * 2. if the header is invalid, status="invalid-update", goto #8
 * 3. display the busy image on-screen
 * 4. if the update image is invalid, status="invalid-radio-image", goto #8
 * 5. attempt to update the firmware (depending on the command)
 * 6. if successful, status="okay", goto #8
 * 7. if failed, and the old image can still boot, status="failed-update"
 * 8. write the recovery_message, leaving the recovery field
 *    unchanged, updating status, and setting command to
 *    "boot-recovery"
 * 9. reboot
 *
 * The bootloader will not modify or erase the cache partition.
 * It is recovery's responsibility to clean up the mess afterwards.
 */

int recovery_init (void)
{
	struct recovery_message msg;
	struct update_header header;
	char partition_name[32];
	unsigned valid_command = 0;
	
	// get recovery message
	if(get_recovery_message(&msg))
		return -1;
	if (msg.command[0] != 0 && msg.command[0] != 255) {
		dprintf(INFO, "Recovery command: %s\n", msg.command);
	}
	msg.command[sizeof(msg.command)-1] = '\0'; //Ensure termination

	if (!strcmp("boot-recovery",msg.command)) {
		valid_command = 1;
		strcpy(msg.command, "");	// to safe against multiple reboot into recovery
		strcpy(msg.status, "OKAY");
		set_recovery_message(&msg);	// send recovery message
		boot_into_recovery = 1;		// Boot in recovery mode
		return 0;
	}

	if (!strcmp("update-radio",msg.command)) {
		valid_command = 1;
		strcpy(partition_name, "AMSS");
	} else if (!strcmp("update-bootloader", msg.command)) {
		valid_command = 1;
		strcpy(partition_name, "bootloader");
	}

	if(!valid_command) {
		//We need not to do anything
		return 0; // Boot in normal mode
	}

	if (read_update_header_for_bootloader(&header)) {
		strcpy(msg.status, "invalid-update");
		goto SEND_RECOVERY_MSG;
	}

	if (update_firmware_image (&header, partition_name)) {
		strcpy(msg.status, "failed-update");
		goto SEND_RECOVERY_MSG;
	}
	strcpy(msg.status, "OKAY");

SEND_RECOVERY_MSG:
	strcpy(msg.command, "boot-recovery");
	set_recovery_message(&msg);	// send recovery message
	boot_into_recovery = 1;		// Boot in recovery mode
	reboot_device(0);
	return 0;
}

#elif defined(TNFTL_V8_INCLUDE)
static int set_recovery_msg_v8(struct recovery_message *out)
{
	char *ptn_name = "misc";
	unsigned long long ptn = 0;
	unsigned int size = ROUND_TO_PAGE(sizeof(*out),511);
	unsigned char data[size];
	
	ptn = flash_ptn_offset(ptn_name);

	if(ptn == 0) {
		dprintf(CRITICAL,"partition %s doesn't exist\n",ptn_name);
		return -1;
	}
	
	memcpy(data, out, sizeof(*out));

	if (flash_write_tnftl_v8(ptn_name, ptn , size, (unsigned int*)data))
	{
		dprintf(CRITICAL,"write failure %s %d\n",ptn_name, sizeof(*out));
		return -1;
	}
	return 0;
}