332 lines
8.6 KiB
C
332 lines
8.6 KiB
C
|
/*
|
|||
|
* * Copyright 2000-2009
|
|||
|
* * Wolfgang Denk, DENX Software Engineering, wd@denx.de.
|
|||
|
* *
|
|||
|
* * SPDX-License-Identifier: GPL-2.0+
|
|||
|
* */
|
|||
|
#include <config.h>
|
|||
|
#include <common.h>
|
|||
|
#include <sparse_format.h>
|
|||
|
#include "sparse.h"
|
|||
|
#include "../sprite_verify.h"
|
|||
|
#include "sunxi_flash.h"
|
|||
|
#include "../cartoon/sprite_cartoon.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 uint last_rest_size;
|
|||
|
static uint 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; //当前数据块需要写入的数据长度
|
|||
|
if (chunk_length == 0) {
|
|||
|
sparse_format_type =
|
|||
|
SPARSE_FORMAT_TYPE_CHUNK_HEAD;
|
|||
|
continue;
|
|||
|
}
|
|||
|
printf("chunk %d(%d)\n", chunk_count++, total_chunks);
|
|||
|
#ifdef CONFIG_SUNXI_SPRITE_CARTOON
|
|||
|
sprite_cartoon_upgrade(10 + (70 * chunk_count)/total_chunks);
|
|||
|
#endif
|
|||
|
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;
|
|||
|
}
|