blob: c65465b479aa599d49d478eddee0fba66eacbde6 [file] [log] [blame]
#include <stdio.h>
#include <inttypes.h>
#include <string.h>
#include "aboot-tiny.h"
#include "jacana_firmware.h"
#include "jacana_pvt.h"
/*---------------------------------------------------------------------------*/
static int
firmware_read_next_to_cache(firmware_handle_t *firmware)
{
size_t size = firmware->end_ptr - firmware->read_ptr;
memmove(firmware->read_ptr - firmware->read_sz, firmware->read_ptr, size);
firmware->read_ptr -= firmware->read_sz;
firmware->end_ptr -= firmware->read_sz;
size_t remainder = firmware->end - firmware->start;
if(remainder > 0) {
size_t size = remainder > firmware->read_sz ? firmware->read_sz : remainder;
int len = jacana_firmware_raw_read(firmware->priv, firmware->start,
(uint8_t *)firmware->middle_ptr, size);
if(len < 0) {
return -1;
}
firmware->start += len;
firmware->end_ptr += len;
}
return 0;
}
/*---------------------------------------------------------------------------*/
int
jacana_firmware_open(firmware_handle_t *firmware, void *priv)
{
firmware->priv = priv;
firmware->start = 0;
firmware->end = jacana_firmware_raw_get_total_size(priv);
firmware->data = aboot_tiny_mem_alloc(MAX_READ_CACHE_SZ * 2);
if(!firmware->data) {
aboot_tiny_log_printf("Failed: can not alloc data buf\n");
return -1;
}
firmware->read_sz = MAX_READ_CACHE_SZ;
firmware->middle_ptr = (char *)firmware->data + firmware->read_sz;
firmware->end_ptr = firmware->middle_ptr + firmware->read_sz;
firmware->read_ptr = firmware->end_ptr;
if(firmware_read_next_to_cache(firmware) < 0) {
goto failed;
}
char cmd_line[ABOOT_COMMAND_SZ];
char magic[9];
uint32_t size;
int num;
if(jacana_firmware_read_line(firmware, cmd_line) <= 0) {
aboot_tiny_log_printf("Failed: can not read a cmd line\n");
goto failed;
}
num = sscanf(cmd_line, "%08s%" SCNx32, magic, &size);
if(num != 2 || size > firmware->end) {
aboot_tiny_log_printf("Failed: cmd line format error\n");
goto failed;
}
firmware->end = (size_t)size;
if(strcmp(magic, "!JACANA!")) {
aboot_tiny_log_printf("Magic error: not a valid firmware\n");
goto failed;
}
return 0;
failed:
aboot_tiny_mem_free(firmware->data);
firmware->data = NULL;
return -1;
}
/*---------------------------------------------------------------------------*/
int
jacana_firmware_read_line(firmware_handle_t *firmware, char *line)
{
while(1) {
if(firmware->read_ptr < firmware->middle_ptr) {
const char *p = (const char *)strchr(firmware->read_ptr, '\n');
if(!p || p >= firmware->end_ptr) {
return -1;
}
int len = p - firmware->read_ptr + 1;
memcpy(line, firmware->read_ptr, len);
line[len] = '\0';
firmware->read_ptr += len;
if(firmware->read_ptr == firmware->end_ptr) {
/* firmware download finished, prepare for continue with pvt */
void *priv = jacana_pvt_raw_open();
if(!priv) {
return -1;
}
jacana_firmware_raw_close(firmware->priv);
jacana_firmware_close(firmware);
if(jacana_pvt_open(firmware, priv) < 0) {
return -1;
}
aboot_tiny_firmware_read_line = jacana_pvt_read_line;
aboot_tiny_firmware_read_data = jacana_pvt_read_data;
}
if(line[0] == '\n') {
continue;
} else {
line[len - 1] = '\0'; /* replace '\n' to '\0' */
return len - 1;
}
} else {
/* read_ptr >= middle_ptr */
if(firmware_read_next_to_cache(firmware) < 0) {
return -1;
}
}
}
}
/*---------------------------------------------------------------------------*/
int
jacana_firmware_read_data(firmware_handle_t *firmware, uint8_t *data, size_t size)
{
while(1) {
if(firmware->read_ptr == firmware->end_ptr) {
return 0;
}
if(firmware->read_ptr < firmware->middle_ptr) {
size_t remainder = firmware->middle_ptr - firmware->read_ptr;
if(remainder < size) {
size = remainder;
}
memcpy(data, firmware->read_ptr, size);
firmware->read_ptr += size;
return size;
} else {
/* read_ptr >= middle_ptr */
if(firmware_read_next_to_cache(firmware) < 0) {
return -1;
}
}
}
}
/*---------------------------------------------------------------------------*/
void
jacana_firmware_close(firmware_handle_t *firmware)
{
firmware->priv = NULL;
firmware->start = 0;
firmware->end = 0;
if(firmware->data) {
aboot_tiny_mem_free(firmware->data);
firmware->data = NULL;
}
firmware->read_sz = 0;
firmware->read_ptr = NULL;
firmware->middle_ptr = NULL;
firmware->end_ptr = NULL;
}
/*---------------------------------------------------------------------------*/