b.liu | ced8dd0 | 2024-06-28 13:28:29 +0800 | [diff] [blame] | 1 | #include <stdio.h> |
| 2 | #include <inttypes.h> |
| 3 | #include <string.h> |
| 4 | |
| 5 | #include "aboot-tiny.h" |
| 6 | #include "jacana_firmware.h" |
| 7 | #include "jacana_pvt.h" |
| 8 | |
| 9 | /*---------------------------------------------------------------------------*/ |
| 10 | static int |
| 11 | firmware_read_next_to_cache(firmware_handle_t *firmware) |
| 12 | { |
| 13 | size_t size = firmware->end_ptr - firmware->read_ptr; |
| 14 | memmove(firmware->read_ptr - firmware->read_sz, firmware->read_ptr, size); |
| 15 | firmware->read_ptr -= firmware->read_sz; |
| 16 | firmware->end_ptr -= firmware->read_sz; |
| 17 | size_t remainder = firmware->end - firmware->start; |
| 18 | if(remainder > 0) { |
| 19 | size_t size = remainder > firmware->read_sz ? firmware->read_sz : remainder; |
| 20 | int len = jacana_firmware_raw_read(firmware->priv, firmware->start, |
| 21 | (uint8_t *)firmware->middle_ptr, size); |
| 22 | if(len < 0) { |
| 23 | return -1; |
| 24 | } |
| 25 | firmware->start += len; |
| 26 | firmware->end_ptr += len; |
| 27 | } |
| 28 | |
| 29 | return 0; |
| 30 | } |
| 31 | /*---------------------------------------------------------------------------*/ |
| 32 | int |
| 33 | jacana_firmware_open(firmware_handle_t *firmware, void *priv) |
| 34 | { |
| 35 | firmware->priv = priv; |
| 36 | firmware->start = 0; |
| 37 | firmware->end = jacana_firmware_raw_get_total_size(priv); |
| 38 | |
| 39 | firmware->data = aboot_tiny_mem_alloc(MAX_READ_CACHE_SZ * 2); |
| 40 | if(!firmware->data) { |
| 41 | aboot_tiny_log_printf("Failed: can not alloc data buf\n"); |
| 42 | return -1; |
| 43 | } |
| 44 | |
| 45 | firmware->read_sz = MAX_READ_CACHE_SZ; |
| 46 | firmware->middle_ptr = (char *)firmware->data + firmware->read_sz; |
| 47 | firmware->end_ptr = firmware->middle_ptr + firmware->read_sz; |
| 48 | firmware->read_ptr = firmware->end_ptr; |
| 49 | if(firmware_read_next_to_cache(firmware) < 0) { |
| 50 | goto failed; |
| 51 | } |
| 52 | |
| 53 | char cmd_line[ABOOT_COMMAND_SZ]; |
| 54 | char magic[9]; |
| 55 | uint32_t size; |
| 56 | int num; |
| 57 | |
| 58 | if(jacana_firmware_read_line(firmware, cmd_line) <= 0) { |
| 59 | aboot_tiny_log_printf("Failed: can not read a cmd line\n"); |
| 60 | goto failed; |
| 61 | } |
| 62 | num = sscanf(cmd_line, "%08s%" SCNx32, magic, &size); |
| 63 | if(num != 2 || size > firmware->end) { |
| 64 | aboot_tiny_log_printf("Failed: cmd line format error\n"); |
| 65 | goto failed; |
| 66 | } |
| 67 | firmware->end = (size_t)size; |
| 68 | if(strcmp(magic, "!JACANA!")) { |
| 69 | aboot_tiny_log_printf("Magic error: not a valid firmware\n"); |
| 70 | goto failed; |
| 71 | } |
| 72 | |
| 73 | return 0; |
| 74 | |
| 75 | failed: |
| 76 | aboot_tiny_mem_free(firmware->data); |
| 77 | firmware->data = NULL; |
| 78 | return -1; |
| 79 | } |
| 80 | /*---------------------------------------------------------------------------*/ |
| 81 | int |
| 82 | jacana_firmware_read_line(firmware_handle_t *firmware, char *line) |
| 83 | { |
| 84 | while(1) { |
| 85 | if(firmware->read_ptr < firmware->middle_ptr) { |
| 86 | const char *p = (const char *)strchr(firmware->read_ptr, '\n'); |
| 87 | if(!p || p >= firmware->end_ptr) { |
| 88 | return -1; |
| 89 | } |
| 90 | int len = p - firmware->read_ptr + 1; |
| 91 | memcpy(line, firmware->read_ptr, len); |
| 92 | line[len] = '\0'; |
| 93 | firmware->read_ptr += len; |
| 94 | if(firmware->read_ptr == firmware->end_ptr) { |
| 95 | /* firmware download finished, prepare for continue with pvt */ |
| 96 | void *priv = jacana_pvt_raw_open(); |
| 97 | if(!priv) { |
| 98 | return -1; |
| 99 | } |
| 100 | jacana_firmware_raw_close(firmware->priv); |
| 101 | jacana_firmware_close(firmware); |
| 102 | if(jacana_pvt_open(firmware, priv) < 0) { |
| 103 | return -1; |
| 104 | } |
| 105 | aboot_tiny_firmware_read_line = jacana_pvt_read_line; |
| 106 | aboot_tiny_firmware_read_data = jacana_pvt_read_data; |
| 107 | } |
| 108 | if(line[0] == '\n') { |
| 109 | continue; |
| 110 | } else { |
| 111 | line[len - 1] = '\0'; /* replace '\n' to '\0' */ |
| 112 | return len - 1; |
| 113 | } |
| 114 | } else { |
| 115 | /* read_ptr >= middle_ptr */ |
| 116 | if(firmware_read_next_to_cache(firmware) < 0) { |
| 117 | return -1; |
| 118 | } |
| 119 | } |
| 120 | } |
| 121 | } |
| 122 | /*---------------------------------------------------------------------------*/ |
| 123 | int |
| 124 | jacana_firmware_read_data(firmware_handle_t *firmware, uint8_t *data, size_t size) |
| 125 | { |
| 126 | while(1) { |
| 127 | if(firmware->read_ptr == firmware->end_ptr) { |
| 128 | return 0; |
| 129 | } |
| 130 | |
| 131 | if(firmware->read_ptr < firmware->middle_ptr) { |
| 132 | size_t remainder = firmware->middle_ptr - firmware->read_ptr; |
| 133 | if(remainder < size) { |
| 134 | size = remainder; |
| 135 | } |
| 136 | memcpy(data, firmware->read_ptr, size); |
| 137 | firmware->read_ptr += size; |
| 138 | return size; |
| 139 | } else { |
| 140 | /* read_ptr >= middle_ptr */ |
| 141 | if(firmware_read_next_to_cache(firmware) < 0) { |
| 142 | return -1; |
| 143 | } |
| 144 | } |
| 145 | } |
| 146 | } |
| 147 | /*---------------------------------------------------------------------------*/ |
| 148 | void |
| 149 | jacana_firmware_close(firmware_handle_t *firmware) |
| 150 | { |
| 151 | firmware->priv = NULL; |
| 152 | firmware->start = 0; |
| 153 | firmware->end = 0; |
| 154 | if(firmware->data) { |
| 155 | aboot_tiny_mem_free(firmware->data); |
| 156 | firmware->data = NULL; |
| 157 | } |
| 158 | firmware->read_sz = 0; |
| 159 | firmware->read_ptr = NULL; |
| 160 | firmware->middle_ptr = NULL; |
| 161 | firmware->end_ptr = NULL; |
| 162 | } |
| 163 | /*---------------------------------------------------------------------------*/ |