1 /*
2 * Copyright (C) 2023 Rockchip Electronics Co., Ltd.
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <stdlib.h>
18 #include <stdio.h>
19 #include <string.h>
20 #include <unistd.h>
21 #include <sys/stat.h>
22 #include <fcntl.h>
23 #include <errno.h>
24 #include <libgen.h>
25 #include <stdbool.h>
26 #include "update.h"
27 #include "log.h"
28 #include "download.h"
29 #include "rkimage.h"
30 #include "flash_image.h"
31 #include "rktools.h"
32 #include "md5sum.h"
33 #include "defineHeader.h"
34 #include "../mtdutils/mtdutils.h"
35
36
37 #define CMD4RECOVERY_FILENAME "/mnt/sdcard/cmd4recovery"
38 #define CMD4RECOVERY_UDISK_FILENAME "/mnt/usb_storage/cmd4recovery"
39 static char * _url = NULL;
40 static char const * _save_path = NULL;
41 static char _url_dir[128];
42 double processvalue = 0;
43
RK_ota_set_url(char * url,char * savepath)44 void RK_ota_set_url(char *url, char *savepath)
45 {
46 LOGI("start RK_ota_url url [%s] save path [%s].\n", url, savepath);
47 if ( url == NULL ) {
48 LOGE("RK_ota_set_url : url is NULL.\n");
49 return ;
50 }
51 if (savepath == NULL) {
52 _save_path = DEFAULT_DOWNLOAD_PATH;
53 } else {
54 _save_path = savepath;
55 }
56 LOGI("save image to %s.\n", _save_path);
57 _url = url;
58
59 sprintf(_url_dir, "%s", _url);
60 dirname(_url_dir);
61 }
62
63 bool is_sdboot = false;
64 bool is_usbboot = false;
65
66 UPDATE_CMD update_cmd[] = {
67 {"bootloader", false, false, 0, 0, 0, "", false, flash_bootloader},
68 {"parameter", false, false, 0, 0, 0, "", false, flash_parameter},
69 {"uboot", false, false, 0, 0, 0, "", false, flash_normal},
70 {"trust", false, false, 0, 0, 0, "", false, flash_normal},
71 {"boot", false, true, 0, 0, 0, "", false, flash_normal},
72 {"recovery", false, false, 0, 0, 0, "", false, flash_normal},
73 {"rootfs", false, true, 0, 0, 0, "", false, flash_normal},
74 {"oem", false, false, 0, 0, 0, "", false, flash_normal},
75 {"uboot_a", false, false, 0, 0, 0, "", false, flash_normal},
76 {"uboot_b", false, false, 0, 0, 0, "", false, flash_normal},
77 {"boot_a", false, false, 0, 0, 0, "", false, flash_normal},
78 {"boot_b", false, false, 0, 0, 0, "", false, flash_normal},
79 {"system_a", false, false, 0, 0, 0, "", false, flash_normal},
80 {"system_b", false, false, 0, 0, 0, "", false, flash_normal},
81 {"misc", false, false, 0, 0, 0, "", false, flash_normal},
82 {"userdata", false, false, 0, 0, 0, "", false, flash_normal},
83 };
84
RK_ota_set_partition(int partition)85 bool RK_ota_set_partition(int partition)
86 {
87 //000000000000000000000000: 没有升级分区
88 //100000000000000000000000: 升级loader分区
89 //010000000000000000000000: 升级parameter分区
90 //001000000000000000000000: 升级uboot分区
91 //000100000000000000000000: 升级trust分区
92 //000010000000000000000000: 升级boot分区
93 //000001000000000000000000: 升级recovery分区
94 //000000100000000000000000: 升级rootfs分区
95 //000000010000000000000000: 升级oem分区
96 //000000001000000000000000: 升级uboot_a分区
97 //000000000100000000000000: 升级uboot_b分区
98 //000000000010000000000000: 升级boot_a分区
99 //000000000001000000000000: 升级boot_b分区
100 //000000000000100000000000: 升级system_a分区
101 //000000000000010000000000: 升级system_b分区
102 //000000000000001000000000: 升级misc分区,sdboot使用
103 //000000000000000100000000: 升级userdata分区
104
105 int num = sizeof(update_cmd) / sizeof(UPDATE_CMD);
106 LOGI("[%s:%d] num [%d]\n", __func__, __LINE__, num);
107
108 if (partition == -1) {
109 //设置目标分区大小
110 RKIMAGE_HDR rkimage_hdr;
111 if ( analyticImage(_url, &rkimage_hdr) != 0) {
112 LOGE("analyticImage error.\n");
113 return false;
114 }
115
116 for (int i = 0; i < num; i++) {
117 if ( update_cmd[i].need_update || is_sdboot || is_usbboot) {
118 update_cmd[i].need_update = false;
119 for (int j = 0; j < rkimage_hdr.item_count; j++) {
120 if (strcmp(rkimage_hdr.item[j].name, update_cmd[i].name) == 0) {
121 LOGI("found rkimage_hdr.item[%d].name = %s.\n", j, update_cmd[i].name);
122 if (rkimage_hdr.item[j].file[50] == 'H') {
123 update_cmd[i].offset = *((DWORD *)(&rkimage_hdr.item[j].file[51]));
124 update_cmd[i].offset <<= 32;
125 update_cmd[i].offset += rkimage_hdr.item[j].offset;
126 LOGI("offset more than 4G, after adjusting is %lld.\n", update_cmd[i].offset);
127 } else {
128 update_cmd[i].offset = rkimage_hdr.item[j].offset;
129 }
130
131 if (rkimage_hdr.item[j].file[55] == 'H') {
132 update_cmd[i].size = *((DWORD *)(&rkimage_hdr.item[j].file[56]));
133 update_cmd[i].size <<= 32;
134 update_cmd[i].size += rkimage_hdr.item[j].size;
135 LOGI("size more than 4G, after adjusting is %lld.\n", update_cmd[i].size);
136 } else {
137 update_cmd[i].size = rkimage_hdr.item[j].size;
138 }
139
140 if (is_sdboot || is_usbboot) {
141 update_cmd[i].flash_offset = (long long)rkimage_hdr.item[j].flash_offset * SECTOR_SIZE;
142 }
143 update_cmd[i].need_update = true;
144 continue ;
145 }
146 }
147 }
148 }
149
150 if (!is_sdboot && !is_usbboot) {
151 for ( int i = 0; i < num; i++ ) {
152 if (*update_cmd[i].dest_path && (update_cmd[i].need_update == false)) {
153
154 unsigned char len = strlen(update_cmd[i].name);
155 if (update_cmd[i].name[len - 2] == '_' && (update_cmd[i].name[len - 1] == 'a' || update_cmd[i].name[len - 1] == 'b')) {
156
157 char slot_find = (update_cmd[i].name[len - 1] == 'a') ? 'b' : 'a';
158
159 update_cmd[i].name[len - 1] = slot_find;
160 for (int j = 0; j < rkimage_hdr.item_count; j++) {
161 if (strcmp(rkimage_hdr.item[j].name, update_cmd[i].name) == 0) {
162 LOGI("again found rkimage_hdr.item[%d].name = %s.\n", j, update_cmd[i].name);
163 if (rkimage_hdr.item[j].file[50] == 'H') {
164 update_cmd[i].offset = *((DWORD *)(&rkimage_hdr.item[j].file[51]));
165 update_cmd[i].offset <<= 32;
166 update_cmd[i].offset += rkimage_hdr.item[j].offset;
167 LOGI("offset more than 4G, after adjusting is %lld.\n", update_cmd[i].offset);
168 } else {
169 update_cmd[i].offset = rkimage_hdr.item[j].offset;
170 }
171
172 if (rkimage_hdr.item[j].file[55] == 'H') {
173 update_cmd[i].size = *((DWORD *)(&rkimage_hdr.item[j].file[56]));
174 update_cmd[i].size <<= 32;
175 update_cmd[i].size += rkimage_hdr.item[j].size;
176 LOGI("size more than 4G, after adjusting is %lld.\n", update_cmd[i].size);
177 } else {
178 update_cmd[i].size = rkimage_hdr.item[j].size;
179 }
180
181 update_cmd[i].need_update = true;
182 continue ;
183 }
184 }
185 }
186 }
187 }
188 }
189 // for ( int i=0; i<num; i++ ) {
190 // printf ( "[%s:%d] update_cmd[%d].name [%s] dest path [%s] flash offset [%#llx] offset [%#llx] size [%#llx] \n",
191 // __func__, __LINE__, i, update_cmd[i].name, update_cmd[i].dest_path, update_cmd[i].flash_offset, update_cmd[i].offset, update_cmd[i].size);
192 // }
193
194 return true;
195 }
196
197 for (int i = 0; i < num; i++) {
198 // For OTA and SD update MUST read gpt from update***.img
199 if ( (partition & 0x800000 || is_sdboot || is_usbboot || (strcmp(update_cmd[i].name, "parameter") == 0) ) ) {
200 LOGI("need update %s.\n", update_cmd[i].name);
201 update_cmd[i].need_update = true;
202
203 if (is_sdboot || is_usbboot) {
204 memset(update_cmd[i].dest_path, 0, sizeof(update_cmd[i].dest_path) / sizeof(update_cmd[i].dest_path[0]));
205 if (strcmp(update_cmd[i].name, "parameter") == 0) {
206 sprintf(update_cmd[i].dest_path, "%s/gpt", _url_dir);
207 } else {
208 sprintf(update_cmd[i].dest_path, "%s/%s", _url_dir, update_cmd[i].name);
209 }
210 } else {
211 if (strcmp(update_cmd[i].name, "parameter") == 0) {
212 sprintf(update_cmd[i].dest_path, "/dev/block/by-name/gpt");
213 } else {
214 if (!isMtdDevice()) {
215 sprintf(update_cmd[i].dest_path, "/dev/block/by-name/%s", update_cmd[i].name);
216 } else {
217 if ( update_cmd[i].need_update && (mtd_scan_partitions() > 0) ) {
218 const MtdPartition *mtdp = mtd_find_partition_by_name(update_cmd[i].name);
219 if (mtdp) {
220 sprintf(update_cmd[i].dest_path, "/dev/mtd%d", mtdp->device_index);
221 LOGI("need update %s ,.dest_path: %s.\n", update_cmd[i].name, update_cmd[i].dest_path);
222 }
223 } else {
224 sprintf(update_cmd[i].dest_path, "/dev/block/by-name/%s", update_cmd[i].name);
225 }
226 }
227 }
228 }
229 }
230 partition = (partition << 1);
231 }
232
233 return true;
234
235 }
236
ota_recovery_cmds(long long flash_offset,const char * dest_path)237 static int ota_recovery_cmds (long long flash_offset, const char *dest_path)
238 {
239 char data_buf[256];
240 unsigned int write_count = 0;
241 int fd = -1;
242 if (dest_path == NULL) {
243 LOGE("[%s-%d] error dest path is NULL.\n", __func__, __LINE__);
244 return -1;
245 }
246
247 LOGI("[%s:%d] parameter flash offset %#llx dest path %s\n", __func__, __LINE__, flash_offset, dest_path);
248 memset(data_buf, 0, sizeof(data_buf) / sizeof(data_buf[0]));
249
250 if (is_sdboot) {
251 fd = open(CMD4RECOVERY_FILENAME, O_CREAT | O_RDWR | O_SYNC | O_APPEND, 0644);
252 if (fd < 0) {
253 LOGE("[%s-%d] error opening %s.\n", __func__, __LINE__, CMD4RECOVERY_FILENAME);
254 return -1;
255 }
256 } else if (is_usbboot) {
257 fd = open(CMD4RECOVERY_UDISK_FILENAME, O_CREAT | O_RDWR | O_SYNC | O_APPEND, 0644);
258 if (fd < 0) {
259 LOGE("[%s-%d] error opening %s.\n", __func__, __LINE__, CMD4RECOVERY_UDISK_FILENAME);
260 return -1;
261 }
262 }
263
264 if (isMtdDevice()) {
265 sprintf(data_buf, "nandwrite -p /dev/mtd0 -s %#llx %s; \n", flash_offset, dest_path);
266 } else {
267 char flash_name[20];
268 getFlashPoint(flash_name);
269
270 #define DD_MALLOC_MAX_SIZE (0x100000*10) /* 10MB */
271
272 unsigned int dd_bs = 0;
273 long long dd_seek = 1;
274
275 for ( int j = DD_MALLOC_MAX_SIZE / SECTOR_SIZE; j > 0 ; j-- ) {
276 dd_bs = j * SECTOR_SIZE;
277 if ( !(flash_offset % dd_bs) ) {
278 dd_seek = flash_offset / dd_bs;
279 LOGI( "flash offset = [%#llx] j=%d bs=%#x seek = %#llx result = [%s]\n",
280 flash_offset, j, dd_bs, dd_seek, (dd_bs * dd_seek == flash_offset) ? "YES" : "NO" );
281 break;
282 } else {
283 dd_bs = 1;
284 dd_seek = flash_offset;
285 }
286 }
287 sprintf(data_buf, "dd of=%s if=%s bs=%d seek=%lld; \t###flash offset [%#10llx] \n", flash_name, dest_path, dd_bs, dd_seek, flash_offset);
288 }
289
290 write_count = strlen(data_buf);
291
292 if (write(fd, data_buf, write_count) != write_count) {
293 close(fd);
294 LOGE("[%s:%d] Write failed(%s)\n", __func__, __LINE__, strerror(errno));
295 return -2;
296 }
297
298 close(fd);
299 return 0;
300 }
301
RK_ota_start(RK_upgrade_callback cb,RK_print_callback print_cb)302 void RK_ota_start(RK_upgrade_callback cb, RK_print_callback print_cb)
303 {
304 LOGI("start RK_ota_start.\n");
305 processvalue = 95;
306 cb(NULL, RK_UPGRADE_START);
307
308 //确认升级路径
309 if (_url == NULL) {
310 LOGE("url is NULL\n");
311 cb(NULL, RK_UPGRADE_ERR);
312 return ;
313 }
314
315 // 1. 获取文件
316 int res = download_file(_url, _save_path);
317 if (res == 0) {
318 _url = (char *)_save_path;
319 } else if (res == -1) {
320 LOGE("download_file error.\n");
321 cb(NULL, RK_UPGRADE_ERR);
322 return ;
323 }
324
325 // 2. 获取文件信息
326 if (!RK_ota_set_partition(-1)) {
327 LOGE("RK_ota_set_partition failed.\n");
328 cb(NULL, RK_UPGRADE_ERR);
329 return ;
330 }
331
332 STRUCT_PARAM_ITEM param_item[20] = {0};
333 long long gpt_backup_offset = -1;
334 memset(param_item, 0, sizeof(param_item));
335 flash_register_partition_data(param_item, &gpt_backup_offset);
336
337 int is_mtd_flag = isMtdDevice();
338
339 // 3. 下载文件到分区并校验
340 int num = sizeof(update_cmd) / sizeof(UPDATE_CMD);
341 char prompt[128] = {0};
342 for (int i = 0; i < num; i++ ) {
343 if (update_cmd[i].need_update) {
344 if (update_cmd[i].cmd != NULL) {
345 LOGI("now write %s to %s.\n", update_cmd[i].name, update_cmd[i].dest_path);
346 sprintf(prompt, "[%s] upgrade start...\n", update_cmd[i].name);
347 print_cb(prompt);
348 if (!is_sdboot && !is_usbboot &&
349 ( (strcmp(update_cmd[i].name, "misc") == 0) ||
350 (strcmp(update_cmd[i].name, "parameter") == 0) )) {
351 LOGI("ingore misc.\n");
352 continue;
353 }
354 // 下载固件到分区
355 LOGI("update_cmd.flash_offset = %lld.\n", update_cmd[i].flash_offset);
356 if (update_cmd[i].cmd(_url, (void*)(&update_cmd[i])) != 0) {
357 LOGE("update %s error.\n", update_cmd[i].dest_path);
358 sprintf(prompt, "[%s] upgrade fail\n", update_cmd[i].name);
359 print_cb(prompt);
360 cb(NULL, RK_UPGRADE_ERR);
361 return ;
362 } else {
363 sprintf(prompt, "[%s] upgraede success!\n", update_cmd[i].name);
364 print_cb(prompt);
365 }
366 if (is_sdboot) {
367 if (ota_recovery_cmds(update_cmd[i].flash_offset, update_cmd[i].dest_path)) {
368 LOGE("write recovery cmds to %s failed.\n", CMD4RECOVERY_FILENAME);
369 cb(NULL, RK_UPGRADE_ERR);
370 return ;
371 }
372 LOGI("not check in sdboot (sdcard).\n");
373 continue;
374 } else if (is_usbboot) {
375 if (ota_recovery_cmds(update_cmd[i].flash_offset, update_cmd[i].dest_path)) {
376 LOGE("write recovery cmds to %s failed.\n", CMD4RECOVERY_UDISK_FILENAME);
377 cb(NULL, RK_UPGRADE_ERR);
378 return ;
379 }
380 LOGI("not check in usb storage (udisk).\n");
381 continue;
382 }
383 // parameter 和loader 先不校验
384 if (strcmp(update_cmd[i].name, "parameter") == 0 || strcmp(update_cmd[i].name, "bootloader") == 0) {
385 LOGI("not check parameter and loader.\n");
386 continue;
387 }
388 // 校验分区
389 if (!update_cmd[i].skip_verify &&
390 comparefile(update_cmd[i].dest_path, _url,
391 update_cmd[i].flash_offset,
392 update_cmd[i].offset, update_cmd[i].size)) {
393 LOGI("check %s ok.\n", update_cmd[i].dest_path);
394 } else if (!update_cmd[i].skip_verify) {
395 LOGE("check %s failed.\n", update_cmd[i].dest_path);
396 cb(NULL, RK_UPGRADE_ERR);
397 return ;
398 }
399 }
400 }
401 }
402
403 /*
404 * Fix if update_xxx.img not found some A/B partition image.
405 */
406 if (is_sdboot || is_usbboot) {
407 for (int i = 0; i < num; i++) {
408 if ( (!update_cmd[i].need_update) || (update_cmd[i].cmd == NULL)) {
409 continue;
410 }
411 unsigned char len = strlen(update_cmd[i].name);
412 if (update_cmd[i].name[len - 2] == '_' && (update_cmd[i].name[len - 1] == 'a' || update_cmd[i].name[len - 1] == 'b') ) {
413 char slot_find = (update_cmd[i].name[len - 1] == 'a') ? 'b' : 'a';
414 int part_need_fix = 1;
415 char part_name[32];
416 memset(part_name, 0, sizeof(part_name) / sizeof(part_name[0]));
417 memcpy(part_name, update_cmd[i].name, len);
418 part_name[len - 1] = slot_find;
419
420 for (int k = 0; k < num; k++) {
421 if ( (!update_cmd[k].need_update) || (update_cmd[k].cmd == NULL)) {
422 continue;
423 }
424 if ( (strcmp(update_cmd[k].name, part_name) == 0) ) {
425 part_need_fix = 0;
426 }
427 }
428
429 if (part_need_fix) {
430 for (int j = 0; j < sizeof(param_item) / sizeof(param_item[0]); j++) {
431 if (strcmp(param_item[j].name, part_name) == 0) {
432 if (ota_recovery_cmds(param_item[j].offset * SECTOR_SIZE, update_cmd[i].dest_path)) {
433 LOGE("sdboot fix write recovery cmds to %s failed.\n", CMD4RECOVERY_FILENAME);
434 cb(NULL, RK_UPGRADE_ERR);
435 return ;
436 }
437 }
438 }
439 }
440 }
441 }
442
443 // write gpt backup
444 /*
445 * char gpt_backup_img_path[100] = {0};
446 * sprintf(gpt_backup_img_path, "%s/%s", _url_dir, GPT_BACKUP_FILE_NAME);
447 * if (ota_recovery_cmds(gpt_backup_offset, gpt_backup_img_path)) {
448 * LOGE("write gpt backup to recovery cmds failed (%s).\n", gpt_backup_img_path);
449 * cb(NULL, RK_UPGRADE_ERR);
450 * return ;
451 * }
452 */
453
454 }
455
456 // 4. 是否设置misc
457
458 LOGI("RK_ota_start is ok!");
459 processvalue = 100;
460 cb(NULL, RK_UPGRADE_FINISHED);
461 print_cb((char *)"updateEngine upgrade OK!\n");
462
463 /* We're successful upgraded, Remove the done_file(see flash_image.cpp) if exist. */
464 {
465 char done_file[256];
466 snprintf(done_file, 256, "%s.done", _url);
467 unlink(done_file);
468 }
469 }
470
RK_ota_get_progress()471 int RK_ota_get_progress()
472 {
473 return processvalue;
474 }
475
RK_ota_get_sw_version(char * buffer,int maxLength)476 void RK_ota_get_sw_version(char *buffer, int maxLength)
477 {
478 getLocalVersion(buffer, maxLength);
479 }
480
RK_ota_check_version(char * url)481 bool RK_ota_check_version(char *url)
482 {
483 char source_version[20] = {0};
484 char target_version[20] = {0};
485 if (!getLocalVersion(source_version, sizeof(source_version))) {
486 return false;
487 }
488
489 if (strncmp(url, "http", 4) == 0) {
490 //如果是远程文件,从远程获取版本号
491 if (!getRemoteVersion(url, target_version, sizeof(target_version))) {
492 return false;
493 }
494 } else {
495 //如果是本地文件,从固件获取版本号
496 if (!getImageVersion(url, target_version, sizeof(target_version))) {
497 return false;
498 }
499 }
500
501 LOGI("check version new:%s old:%s", target_version, source_version);
502 if (strcmp(target_version, source_version) > 0) {
503 return true;
504 }
505 return false;
506 }
507