| #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; |
| } |
| /*---------------------------------------------------------------------------*/ |