#include <mmc.h>
#include <div64.h>
+static ext4_chunk_header chunk_header;
+static ext4_file_header *file_header;
+static int total_chunks;
+static int remain_chunk_sectors;
+static unsigned int sector_base;
+
+static int residue_bytes;
+static char residue_buf[512];
+
#define SECTOR_BITS 9 /* 512B */
+#define SECTOR_SIZE (1 << SECTOR_BITS)
#define ext4_printf(args, ...)
return 0;
}
-int write_compressed_ext4(char* img_base, unsigned int sector_base) {
- unsigned int sector_size;
- int total_chunks;
- ext4_chunk_header *chunk_header;
- ext4_file_header *file_header;
+ext4_file_header *init_compressed_ext4(char *img_base)
+{
+ ext4_file_header *f_hdr;
- file_header = (ext4_file_header*)img_base;
- total_chunks = file_header->total_chunks;
+ f_hdr = (ext4_file_header *)malloc(sizeof(ext4_file_header));
+ if (!f_hdr)
+ return NULL;
- ext4_printf("total chunk = %d \n", total_chunks);
+ memcpy(f_hdr, img_base, sizeof(ext4_file_header));
+ total_chunks = f_hdr->total_chunks;
+ ext4_printf("total chunk = %d\n", total_chunks);
- img_base += EXT4_FILE_HEADER_SIZE;
+ return f_hdr;
+}
- while(total_chunks) {
- chunk_header = (ext4_chunk_header*)img_base;
- sector_size = (chunk_header->chunk_size * file_header->block_size) >> SECTOR_BITS;
+void exit_compressed_ext4(void)
+{
+ if (file_header)
+ free(file_header);
+ file_header = NULL;
+ total_chunks = 0;
+ remain_chunk_sectors = 0;
+ residue_bytes = 0;
+ sector_base = 0;
+}
- switch(chunk_header->type)
- {
+int write_compressed_ext4(char *img_base, unsigned int buflen,
+ unsigned int base, unsigned int length)
+{
+ unsigned int sector_size;
+ int remain_bytes = buflen;
+
+ if (!file_header) {
+ /* If there is no file_header, it means the first download
+ * stage. First of all, we need to parse the file header */
+ file_header = init_compressed_ext4(img_base);
+ if (!file_header)
+ return -1;
+ img_base += file_header->file_header_size;
+ remain_bytes -= file_header->file_header_size;
+ sector_base = base;
+ }
+
+ /* Flash buffer until there is no remain buffer */
+ while (remain_bytes > 0) {
+ if (!remain_chunk_sectors) {
+ if (remain_bytes < sizeof(ext4_chunk_header)) {
+ printf("Cannot parse chunk_header\n");
+ return -1;
+ }
+
+ memcpy(&chunk_header, img_base,
+ sizeof(ext4_chunk_header));
+ img_base += file_header->chunk_header_size;
+ remain_bytes -= file_header->chunk_header_size;
+
+ sector_size = (chunk_header.chunk_size *
+ file_header->block_size) >> SECTOR_BITS;
+ remain_chunk_sectors = sector_size;
+ } else
+ sector_size = remain_chunk_sectors;
+
+ switch (chunk_header.type) {
case EXT4_CHUNK_TYPE_RAW:
- ext4_printf("raw_chunk \n");
- write_raw_chunk(img_base + EXT4_CHUNK_HEADER_SIZE,
- sector_base, sector_size);
- sector_base += sector_size;
+ ext4_printf("raw_chunk\n");
+ if (residue_bytes) {
+ /* If there is residue buffer, fill a sector
+ * and flash it */
+ memcpy(residue_buf + residue_bytes, img_base,
+ SECTOR_SIZE - residue_bytes);
+ write_raw_chunk(residue_buf, sector_base, 1);
+ /* Move a location of sector base */
+ sector_base++;
+ img_base += (SECTOR_SIZE - residue_bytes);
+ sector_size--;
+ remain_chunk_sectors--;
+ remain_bytes -= (SECTOR_SIZE - residue_bytes);
+ residue_bytes = 0;
+ }
+
+ if (sector_size > (remain_bytes >> SECTOR_BITS)) {
+ /* If we need to keep residue buffer, we store
+ * them into residue_buf and flash them during
+ * next download */
+ residue_bytes = remain_bytes -
+ ((remain_bytes >> SECTOR_BITS)
+ << SECTOR_BITS);
+ sector_size = remain_bytes >> SECTOR_BITS;
+ if (residue_bytes) {
+ memcpy(residue_buf, img_base +
+ (sector_size << SECTOR_BITS),
+ residue_bytes);
+ }
+ }
+
+ if (sector_size) {
+ write_raw_chunk(img_base, sector_base,
+ sector_size);
+ sector_base += sector_size;
+ img_base += (sector_size << SECTOR_BITS);
+ remain_bytes -= ((sector_size << SECTOR_BITS)
+ + residue_bytes);
+ }
break;
case EXT4_CHUNK_TYPE_FILL:
- printf("*** fill_chunk ***\n");
sector_base += sector_size;
+ img_base += (chunk_header.total_size -
+ file_header->chunk_header_size);
+ remain_bytes -= (chunk_header.total_size -
+ file_header->chunk_header_size);
break;
case EXT4_CHUNK_TYPE_NONE:
- ext4_printf("none chunk \n");
+ ext4_printf("none chunk\n");
sector_base += sector_size;
+ img_base += (chunk_header.total_size -
+ file_header->chunk_header_size);
+ remain_bytes -= (chunk_header.total_size -
+ file_header->chunk_header_size);
break;
default:
- printf("*** unknown chunk type ***\n");
- sector_base += sector_size;
- break;
+ ext4_printf("*** unknown chunk type ***\n");
+ /* If unknown chunk type is founded, return error */
+ exit_compressed_ext4();
+ return -1;
}
- total_chunks--;
- ext4_printf("remain chunks = %d \n", total_chunks);
-
- img_base += chunk_header->total_size;
+ remain_chunk_sectors -= sector_size;
+ if (remain_chunk_sectors == 0)
+ total_chunks--;
+
+ if (total_chunks == 0) {
+ ext4_printf("write done\n");
+ exit_compressed_ext4();
+ return 0;
+ }
+ ext4_printf("remain chunks = %d\n", total_chunks);
};
- ext4_printf("write done \n");
return 0;
}