SmartAudio/lichee/brandy/u-boot-2014.07/sprite/sparse/sparse.c

339 lines
10 KiB
C
Raw Normal View History

2018-07-13 01:31:50 +00:00
/*
* (C) Copyright 2007-2013
* Allwinner Technology Co., Ltd. <www.allwinnertech.com>
* Jerry Wang <wangflord@allwinnertech.com>
*
* See file CREDITS for list of people who contributed to this
* project.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License as
* published by the Free Software Foundation; either version 2 of
* the License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston,
* MA 02111-1307 USA
*/
#include <config.h>
#include <common.h>
#include <sparse_format.h>
#include "sparse.h"
#include "../sprite_verify.h"
#define SPARSE_FORMAT_TYPE_TOTAL_HEAD 0xff00
#define SPARSE_FORMAT_TYPE_CHUNK_HEAD 0xff01
#define SPARSE_FORMAT_TYPE_CHUNK_DATA 0xff02
#define SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA 0xff03
static uint android_format_checksum;
static uint sparse_format_type;
static uint chunk_count;
static int last_rest_size;
static int chunk_length;
static uint flash_start;
static sparse_header_t globl_header;
static uint total_chunks;
/*
************************************************************************************************************
*
* unsparse_probe
*
*
*
*
*
*
*
*
*
*
************************************************************************************************************
*/
int unsparse_probe(char *source, uint length, uint android_format_flash_start)
{
sparse_header_t *header = (sparse_header_t*) source;
if (header->magic != SPARSE_HEADER_MAGIC)
{
printf("sparse: bad magic\n");
return ANDROID_FORMAT_BAD;
}
if ((header->major_version != SPARSE_HEADER_MAJOR_VER) ||
(header->file_hdr_sz != sizeof(sparse_header_t)) ||
(header->chunk_hdr_sz != sizeof(chunk_header_t)))
{
printf("sparse: incompatible format\n");
return ANDROID_FORMAT_BAD;
}
android_format_checksum = 0;
last_rest_size = 0;
chunk_count = 0;
chunk_length = 0;
sparse_format_type = SPARSE_FORMAT_TYPE_TOTAL_HEAD;
flash_start = android_format_flash_start;
total_chunks = header->total_chunks;
return ANDROID_FORMAT_DETECT;
}
/*
************************************************************************************************************
*
* DRAM_Write
*
*
*
*
*
*
*
*
*
*
************************************************************************************************************
*/
int unsparse_direct_write(void *pbuf, uint length)
{
int unenough_length;
int this_rest_size;
int tmp_down_size;
char *tmp_buf, *tmp_dest_buf;
chunk_header_t *chunk;
//首先计算传进的数据的校验和
android_format_checksum += add_sum(pbuf, length);
this_rest_size = last_rest_size + length;
tmp_buf = (char *)pbuf - last_rest_size;
last_rest_size = 0;
while(this_rest_size > 0)
{
switch(sparse_format_type)
{
case SPARSE_FORMAT_TYPE_TOTAL_HEAD:
{
memcpy(&globl_header, tmp_buf, sizeof(sparse_header_t));
this_rest_size -= sizeof(sparse_header_t);
tmp_buf += sizeof(sparse_header_t);
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_HEAD;
break;
}
case SPARSE_FORMAT_TYPE_CHUNK_HEAD:
{
if(this_rest_size < sizeof(chunk_header_t))
{
printf("sparse: chunk head data is not enough\n");
last_rest_size = this_rest_size;
tmp_dest_buf = (char *)pbuf - this_rest_size;
memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
this_rest_size = 0;
break;
}
chunk = (chunk_header_t *)tmp_buf;
/* move to next chunk */
tmp_buf += sizeof(chunk_header_t); //此时tmp_buf已经指向下一个chunk或者data起始地址
this_rest_size -= sizeof(chunk_header_t); //剩余的数据长度
chunk_length = chunk->chunk_sz * globl_header.blk_sz; //当前数据块需要写入的数据长度
printf("chunk %d(%d)\n", chunk_count ++, total_chunks);
switch (chunk->chunk_type)
{
case CHUNK_TYPE_RAW:
if (chunk->total_sz != (chunk_length + sizeof(chunk_header_t)))
{
printf("sparse: bad chunk size for chunk %d, type Raw\n", chunk_count);
return -1;
}
//这里不处理数据部分,转到下一个状态
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_DATA;
break;
case CHUNK_TYPE_FILL:
if(chunk->total_sz != sizeof(chunk_header_t) + sizeof(u32))
{
printf("spase : bad chunk size for chunk ,type FILL \n");
return -1;
}
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA;
break;
case CHUNK_TYPE_DONT_CARE:
if (chunk->total_sz != sizeof(chunk_header_t))
{
printf("sparse: bogus DONT CARE chunk\n");
return -1;
}
flash_start += (chunk_length>>9);
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_HEAD;
break;
default:
printf("sparse: unknown chunk ID %x\n", chunk->chunk_type);
return -1;
}
break;
}
case SPARSE_FORMAT_TYPE_CHUNK_DATA:
{
//首先判断数据是否足够当前chunk所需,如果不足,则计算出还需要的数据长度
unenough_length = (chunk_length >= this_rest_size)? (chunk_length - this_rest_size):0;
if(!unenough_length)
{
//数据足够,直接写入
if(!sunxi_sprite_write(flash_start, chunk_length>>9, tmp_buf))
{
printf("sparse: flash write failed\n");
return -1;
}
if(chunk_length & 511)
{
printf("data is not sector align 0\n");
return -1;
}
flash_start += (chunk_length>>9);
tmp_buf += chunk_length;
this_rest_size -= chunk_length;
chunk_length = 0;
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_HEAD;
}
else //存在缺失数据的情况
{
if(this_rest_size < 8 * 1024) //先看已有数据是否不足8k
{
//当不足时,把这笔数据放到下一笔数据的前部,等待下一次处理
tmp_dest_buf = (char *)pbuf - this_rest_size;
memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
last_rest_size = this_rest_size;
this_rest_size = 0;
break;
}
//当已有数据超过16k时
//当缺失数据长度不足4k时,可能只缺几十个字节
if(unenough_length < 4 * 1024)
{
//采用拼接方法,先烧写部分已有数据,然后在下一次把未烧写的已有数据和缺失数据一起烧录
tmp_down_size = this_rest_size + unenough_length - 4 * 1024;
}
else //这里处理缺失数据超过8k(包含)的情况,同时已有数据也超过16k
{
//直接烧录当前全部数据;
tmp_down_size = this_rest_size & (~(512 -1)); //扇区对齐
}
if(!sunxi_sprite_write(flash_start, tmp_down_size>>9, tmp_buf))
{
printf("sparse: flash write failed\n");
return -1;
}
if(tmp_down_size & 511)
{
printf("data is not sector align 1\n");
return -1;
}
tmp_buf += tmp_down_size;
flash_start += (tmp_down_size>>9);
chunk_length -= tmp_down_size;
this_rest_size -= tmp_down_size;
tmp_dest_buf = (char *)pbuf - this_rest_size;
memcpy(tmp_dest_buf, tmp_buf, this_rest_size);
last_rest_size = this_rest_size;
this_rest_size = 0;
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_DATA;
}
break;
}
case SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA:
{
u32 fillbuf[1024];
u32 file_val = 0;
u32 ii = 0;
if(this_rest_size >= 4)
{
this_rest_size -= sizeof(u32);
file_val = *(int *)tmp_buf;
if (chunk_length & 511) {
printf("fill data is not sector align 0\n");
return -1;
}
for (ii = 0; ii < sizeof(fillbuf)/sizeof(fillbuf[0]); ii++)
fillbuf[ii] = file_val;
for (ii = 0; ii < (chunk_length>>12); ii++) {
if (!sunxi_sprite_write(flash_start, 8, fillbuf)) {
printf("sparse: fill data write failed\n");
return -1;
}
flash_start += 8;
}
tmp_buf += sizeof(u32);
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_HEAD;
}
else
{
tmp_dest_buf = (char *)pbuf - this_rest_size;
memcpy(tmp_dest_buf,tmp_buf,this_rest_size);
last_rest_size = this_rest_size;
this_rest_size = 0;
sparse_format_type = SPARSE_FORMAT_TYPE_CHUNK_FILL_DATA;
}
break;
}
default:
{
printf("sparse: unknown status\n");
return -1;
}
}
}
return 0;
}
/*
************************************************************************************************************
*
* unsparse_checksum
*
*
*
*
*
*
*
*
*
*
************************************************************************************************************
*/
uint unsparse_checksum(void)
{
return android_format_checksum;
}