b.liu | ced8dd0 | 2024-06-28 13:28:29 +0800 | [diff] [blame^] | 1 | #include <string.h> |
| 2 | |
| 3 | #include "aboot-tiny.h" |
| 4 | #include "jacana_pvt.h" |
| 5 | |
| 6 | /*---------------------------------------------------------------------------*/ |
| 7 | static const char *jacana_pvt_cmd_resp[] = { |
| 8 | "getvar:max-download-size", /* 0 */ |
| 9 | "OKAY\t%08x", /* 1 */ |
| 10 | "download:%08x", /* 2 */ |
| 11 | "DATA%08x", /* 3 */ |
| 12 | "OKAY", /* 4 */ |
| 13 | "flash:pvt", /* 5 */ |
| 14 | "OKAY" /* 6 */ |
| 15 | }; |
| 16 | /*---------------------------------------------------------------------------*/ |
| 17 | static int |
| 18 | pvt_read_next_to_cache(firmware_handle_t *firmware) |
| 19 | { |
| 20 | size_t size = firmware->end_ptr - firmware->read_ptr; |
| 21 | memmove(firmware->read_ptr - firmware->read_sz, firmware->read_ptr, size); |
| 22 | firmware->read_ptr -= firmware->read_sz; |
| 23 | firmware->end_ptr -= firmware->read_sz; |
| 24 | size_t remainder = firmware->end - firmware->start; |
| 25 | if(remainder > 0) { |
| 26 | size_t size = remainder > firmware->read_sz ? firmware->read_sz : remainder; |
| 27 | int len = jacana_pvt_raw_read(firmware->priv, firmware->start, |
| 28 | (uint8_t *)firmware->middle_ptr, size); |
| 29 | if(len < 0) { |
| 30 | return -1; |
| 31 | } |
| 32 | firmware->start += len; |
| 33 | firmware->end_ptr += len; |
| 34 | } |
| 35 | |
| 36 | return 0; |
| 37 | } |
| 38 | /*---------------------------------------------------------------------------*/ |
| 39 | int |
| 40 | jacana_pvt_open(firmware_handle_t *firmware, void *priv) |
| 41 | { |
| 42 | firmware->priv = priv; |
| 43 | firmware->start = 0; |
| 44 | firmware->end = jacana_pvt_raw_get_total_size(priv); |
| 45 | |
| 46 | pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| 47 | pvt_info->max_download_size = aboot_tiny_get_max_download_size(); |
| 48 | if(pvt_info->max_download_size > 8192) { |
| 49 | pvt_info->max_download_size = 8192; |
| 50 | } |
| 51 | pvt_info->offset = 0; |
| 52 | pvt_info->state = 0; |
| 53 | |
| 54 | firmware->data = aboot_tiny_mem_alloc(MAX_READ_CACHE_SZ * 2); |
| 55 | if(!firmware->data) { |
| 56 | aboot_tiny_log_printf("Failed: can not alloc data buf\n"); |
| 57 | return -1; |
| 58 | } |
| 59 | |
| 60 | firmware->read_sz = MAX_READ_CACHE_SZ; |
| 61 | firmware->middle_ptr = (char *)firmware->data + firmware->read_sz; |
| 62 | firmware->end_ptr = firmware->middle_ptr + firmware->read_sz; |
| 63 | firmware->read_ptr = firmware->end_ptr; |
| 64 | if(pvt_read_next_to_cache(firmware) < 0) { |
| 65 | aboot_tiny_mem_free(firmware->data); |
| 66 | firmware->data = NULL; |
| 67 | return -1; |
| 68 | } |
| 69 | |
| 70 | sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| 71 | size_t remainder = firmware->end - firmware->start; |
| 72 | size_t size = (pvt_info->max_download_size |
| 73 | - SPARSE_FILE_HEADER_SIZE |
| 74 | - SPARSE_FILE_FOOTER_SIZE) & ~(SPARSE_BLOCK_SZ - 1); |
| 75 | if(remainder < size) { |
| 76 | size = remainder; |
| 77 | } |
| 78 | |
| 79 | sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| 80 | pvt_info->offset += size; |
| 81 | |
| 82 | return 0; |
| 83 | } |
| 84 | /*---------------------------------------------------------------------------*/ |
| 85 | int |
| 86 | jacana_pvt_read_line(firmware_handle_t *firmware, char *line) |
| 87 | { |
| 88 | pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| 89 | sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| 90 | |
| 91 | switch(pvt_info->state) { |
| 92 | case 0: |
| 93 | case 4: |
| 94 | case 5: |
| 95 | case 6: |
| 96 | strcpy(line,jacana_pvt_cmd_resp[pvt_info->state]); |
| 97 | break; |
| 98 | |
| 99 | case 1: |
| 100 | sprintf(line, jacana_pvt_cmd_resp[pvt_info->state], |
| 101 | pvt_info->max_download_size); |
| 102 | break; |
| 103 | case 2: |
| 104 | case 3: |
| 105 | sprintf(line, jacana_pvt_cmd_resp[pvt_info->state], |
| 106 | sparse_file->header_size |
| 107 | + sparse_file->data_size |
| 108 | + sparse_file->fill_size |
| 109 | + sparse_file->footer_size); |
| 110 | break; |
| 111 | |
| 112 | case 7: /* pvt command sequence finished */ |
| 113 | if(firmware->start < firmware->end) { |
| 114 | pvt_info->state = 0; |
| 115 | |
| 116 | size_t remainder = firmware->end - firmware->start; |
| 117 | size_t size = (pvt_info->max_download_size |
| 118 | - SPARSE_FILE_HEADER_SIZE |
| 119 | - SPARSE_FILE_FOOTER_SIZE) & ~(SPARSE_BLOCK_SZ - 1); |
| 120 | if(remainder < size) { |
| 121 | size = remainder; |
| 122 | } |
| 123 | sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| 124 | pvt_info->offset += size; |
| 125 | return jacana_pvt_read_line(firmware, line); |
| 126 | } else { |
| 127 | if(pvt_info->offset < firmware->end) { |
| 128 | /* remainder data in cache */ |
| 129 | pvt_info->state = 0; |
| 130 | size_t size = firmware->end - pvt_info->offset; |
| 131 | sparse_file_new(sparse_file, pvt_info->offset, size, firmware->end); |
| 132 | pvt_info->offset += size; |
| 133 | return jacana_pvt_read_line(firmware, line); |
| 134 | } else { |
| 135 | /* all finished */ |
| 136 | return 0; |
| 137 | } |
| 138 | } |
| 139 | |
| 140 | default: |
| 141 | return -1; |
| 142 | } |
| 143 | pvt_info->state++; |
| 144 | |
| 145 | return strlen(line); |
| 146 | } |
| 147 | /*---------------------------------------------------------------------------*/ |
| 148 | int |
| 149 | jacana_pvt_read_data(firmware_handle_t *firmware, uint8_t *data, size_t size) |
| 150 | { |
| 151 | pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| 152 | sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| 153 | |
| 154 | if(sparse_file->header_size) { |
| 155 | if(sparse_file->header_size > size) { |
| 156 | /* should not happen */ |
| 157 | return -1; |
| 158 | } else { |
| 159 | size = sparse_file->header_size; |
| 160 | memcpy(data, sparse_file->header, size); |
| 161 | sparse_file->header_size = 0; |
| 162 | return size; |
| 163 | } |
| 164 | } |
| 165 | |
| 166 | if(sparse_file->footer_size == 0) { |
| 167 | /* should not happen */ |
| 168 | return -1; |
| 169 | } |
| 170 | |
| 171 | if(sparse_file->data_size == 0) { |
| 172 | if(sparse_file->fill_size) { |
| 173 | if(size > sparse_file->fill_size) { |
| 174 | size = sparse_file->fill_size; |
| 175 | } |
| 176 | memset(data, 0, size); |
| 177 | sparse_file->fill_size -= size; |
| 178 | return size; |
| 179 | } else if(sparse_file->footer_size > size) { |
| 180 | /* should not happen */ |
| 181 | return -1; |
| 182 | } else { |
| 183 | /* footer_size <= size */ |
| 184 | size = sparse_file->footer_size; |
| 185 | memcpy(data, sparse_file->footer, size); |
| 186 | sparse_file->footer_size = 0; |
| 187 | return size; |
| 188 | } |
| 189 | } |
| 190 | |
| 191 | if(sparse_file->data_size < size) { |
| 192 | size = sparse_file->data_size; |
| 193 | } |
| 194 | |
| 195 | while(1) { |
| 196 | if(firmware->read_ptr == firmware->end_ptr) { |
| 197 | /* should not happen */ |
| 198 | return -1; |
| 199 | } |
| 200 | if(firmware->read_ptr < firmware->middle_ptr) { |
| 201 | size_t remainder = firmware->middle_ptr - firmware->read_ptr; |
| 202 | if(remainder < size) { |
| 203 | size = remainder; |
| 204 | } |
| 205 | memcpy(data, firmware->read_ptr, size); |
| 206 | firmware->read_ptr += size; |
| 207 | break; |
| 208 | } else { |
| 209 | /* read_ptr >= middle_ptr */ |
| 210 | if(pvt_read_next_to_cache(firmware) < 0) { |
| 211 | return -1; |
| 212 | } |
| 213 | } |
| 214 | } |
| 215 | |
| 216 | sparse_file->data_size -= size; |
| 217 | |
| 218 | return size; |
| 219 | } |
| 220 | /*---------------------------------------------------------------------------*/ |
| 221 | void |
| 222 | jacana_pvt_close(firmware_handle_t *firmware) |
| 223 | { |
| 224 | firmware->priv = NULL; |
| 225 | firmware->start = 0; |
| 226 | firmware->end = 0; |
| 227 | |
| 228 | if(firmware->data) { |
| 229 | aboot_tiny_mem_free(firmware->data); |
| 230 | firmware->data = NULL; |
| 231 | } |
| 232 | firmware->read_sz = 0; |
| 233 | firmware->read_ptr = NULL; |
| 234 | firmware->middle_ptr = NULL; |
| 235 | firmware->end_ptr = NULL; |
| 236 | |
| 237 | pvt_info_t *pvt_info = (pvt_info_t *)firmware->pvt_info; |
| 238 | pvt_info->max_download_size = 0; |
| 239 | pvt_info->state = 0; |
| 240 | |
| 241 | sparse_file_t *sparse_file = &pvt_info->sparse_file; |
| 242 | memset(sparse_file->header, 0, SPARSE_FILE_HEADER_SIZE); |
| 243 | sparse_file->header_size = 0; |
| 244 | sparse_file->data_size = 0; |
| 245 | } |
| 246 | /*---------------------------------------------------------------------------*/ |