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 <stdio.h>
18 #include <string.h>
19 #include <stdlib.h>
20 #include <unistd.h>
21 #include <getopt.h>
22 #include <sys/reboot.h>
23 #include "log.h"
24 #include "update.h"
25 #include "../bootloader.h"
26 #include "../recovery_version.h"
27 #include "defineHeader.h"
28 #include "rktools.h"
29
30 extern bool is_sdboot;
31 extern bool is_usbboot;
32 static bool rkdebug = false;
33 static char *ui_rotation = NULL;
34 static const char *update_engine_version = RECOVERY_VERSION_STRING;
35
36 RK_Upgrade_Status_t m_status = RK_UPGRADE_ERR;
37 FILE* cmd_pipe = NULL;
38
handle_upgrade_callback(void * user_data,RK_Upgrade_Status_t status)39 void handle_upgrade_callback(void *user_data, RK_Upgrade_Status_t status)
40 {
41 if (status == RK_UPGRADE_FINISHED) {
42 LOGI("rk ota success.\n");
43 setSlotActivity();
44 }
45 m_status = status;
46 LOGI("rk m_status = %d.\n", m_status);
47 }
48
handle_print_callback(char * szPrompt)49 void handle_print_callback(char *szPrompt)
50 {
51 if (cmd_pipe != NULL) {
52 fprintf(cmd_pipe, "ui_print %s\n", szPrompt);
53 }
54 }
55
MiscUpdate(char * url,char * update_partition,char * save_path)56 static int MiscUpdate(char *url, char *update_partition, char *save_path)
57 {
58 int partition;
59 char *savepath = NULL;
60 int slot = -1;
61 if (url == NULL) {
62 //如果没有传入URL,则可以去查找是否有存在
63 LOGE("MiscUpdate URL must be set.\n");
64 return -1;
65 }
66 slot = getCurrentSlot();
67 if (update_partition == NULL) {
68 //没有传入要升级的分区,默认升级
69 if (slot == -1) {
70 // recovery mdoe
71 // u-boot/trust/boot/recovery/boot/rootfs/oem
72 partition = 0X3F0000;
73 } else {
74 // A/B mdoe
75 // uboot_a/uboot_b/boot_a/boot_b/system_a/system_b
76 partition = 0XFC00;
77 }
78 } else {
79 partition = strtol(update_partition + 2, NULL, 16);
80 }
81
82 if (save_path == NULL) {
83 savepath = url;
84 } else {
85 savepath = save_path;
86 }
87
88 RK_ota_set_url(url, savepath);
89 LOGI("url = %s.\n", url);
90 LOGI("[%s:%d] save path: %s\n", __func__, __LINE__, savepath);
91 // If it's recovery mode, upgrade recovery in normal system.
92 if (slot == -1 && !is_sdboot && !is_usbboot) {
93 if (partition & 0x040000) {
94 LOGI("update recovery in normal system.\n");
95 partition = partition & 0xFBFFFF;
96
97 // upgrade recoery in normal system
98 if (!RK_ota_set_partition(0x040000)) {
99 LOGE("ota file is error.\n");
100 return -1;
101 }
102 RK_ota_start(handle_upgrade_callback, handle_print_callback);
103 if (m_status != RK_UPGRADE_FINISHED) {
104 return -1;
105 }
106
107 //写MISC
108 struct bootloader_message msg;
109 memset(&msg, 0, sizeof(msg));
110 char recovery_str[] = "recovery\n--update_package=";
111 strcpy(msg.command, "boot-recovery");
112 sprintf(msg.recovery, "%s%s\n", recovery_str, savepath);
113 memcpy(msg.needupdate, &partition, 4);
114 if (true == rkdebug) {
115 strcat(msg.recovery, "--rkdebug\n");
116 }
117 if (NULL != ui_rotation) {
118 strcat(msg.recovery, "--ui_rotation=");
119 strcat(msg.recovery, ui_rotation);
120 msg.recovery[strlen(msg.recovery)] = '\n';
121 }
122 set_bootloader_message(&msg);
123 return 0;
124 }
125 } else if (slot == 0) {
126 LOGI("In A system, now upgrade B system.\n");
127 partition = partition & 0x155ff;
128 } else if (slot == 1) {
129 LOGI("In B system, now upgrade A system.\n");
130 partition = partition & 0x1a9ff;
131 }
132
133 if (!RK_ota_set_partition(partition)) {
134 LOGE("ota file is error.\n");
135 return -1;
136 }
137 RK_ota_start(handle_upgrade_callback, handle_print_callback);
138 if (m_status != RK_UPGRADE_FINISHED) {
139 return -1;
140 }
141
142 return 0;
143 }
144
display(void)145 void display(void)
146 {
147 LOGI("--misc=now Linux A/B mode: Setting the current partition to bootable.\n");
148 LOGI("--misc=other Linux A/B mode: Setting another partition to bootable.\n");
149 LOGI("--misc=update Recovery mode: Setting the partition to be upgraded.\n");
150 LOGI("--misc=display Display misc info.\n");
151 LOGI("--misc=wipe_userdata Format data partition.\n");
152 LOGI("--misc_custom= < op > Operation on misc for custom cmdline");
153 LOGI(" op: read Read custom cmdline to /tmp/custom_cmdline");
154 LOGI(" write Write /tmp/custom_cmdline to custom area");
155 LOGI(" clean clean custom area");
156 LOGI("--update Upgrade mode.\n");
157 LOGI("--partition=0x3FFC00 Set the partition to be upgraded.(NOTICE: OTA not support upgrade loader and parameter)\n");
158 LOGI(" 0x3FFC00: 0011 1111 1111 1100 0000 0000.\n");
159 LOGI(" uboot trust boot recovery rootfs oem\n");
160 LOGI(" uboot_a uboot_b boot_a boot_b system_a system_b.\n");
161 LOGI(" 100000000000000000000000: Upgrade loader\n");
162 LOGI(" 010000000000000000000000: Upgrade parameter\n");
163 LOGI(" 001000000000000000000000: Upgrade uboot\n");
164 LOGI(" 000100000000000000000000: Upgrade trust\n");
165 LOGI(" 000010000000000000000000: Upgrade boot\n");
166 LOGI(" 000001000000000000000000: Upgrade recovery\n");
167 LOGI(" 000000100000000000000000: Upgrade rootfs\n");
168 LOGI(" 000000010000000000000000: Upgrade oem\n");
169 LOGI(" 000000001000000000000000: Upgrade uboot_a\n");
170 LOGI(" 000000000100000000000000: Upgrade uboot_b\n");
171 LOGI(" 000000000010000000000000: Upgrade boot_a\n");
172 LOGI(" 000000000001000000000000: Upgrade boot_b\n");
173 LOGI(" 000000000000100000000000: Upgrade system_a\n");
174 LOGI(" 000000000000010000000000: Upgrade system_b\n");
175 LOGI(" 000000000000001000000000: Upgrade misc\n");
176 LOGI(" 000000000000000100000000: Upgrade userdata\n");
177 LOGI("--reboot Restart the machine at the end of the program.\n");
178 LOGI("--version_url=url The path to the file of version.\n");
179 LOGI("--image_url=url Path to upgrade firmware.\n");
180 LOGI("--savepath=url save the update.img to url.\n");
181 LOGI("--version the version of updateEngine\n");
182 LOGI("--rkdebug Log output to serial port\n");
183 LOGI("--ui_rotation UI rotation,has 4 angles(0-3).\n");
184
185 }
186
187 static const struct option engine_options[] = {
188 { "update", optional_argument, NULL, 'u' },
189 { "version_url", required_argument, NULL, 'v' + 'u' },
190 { "image_url", required_argument, NULL, 'i' + 'u'},
191 { "check", required_argument, NULL, 'c' },
192 { "misc", required_argument, NULL, 'm' },
193 { "misc_custom", required_argument, NULL, 'd' },
194 { "partition", required_argument, NULL, 'p' },
195 { "reboot", no_argument, NULL, 'r' },
196 { "help", no_argument, NULL, 'h' },
197 { "pipefd", required_argument, NULL, 'p' + 'f' },
198 { "savepath", required_argument, NULL, 's'},
199 { "version", no_argument, NULL, 'v'},
200 { "rkdebug", no_argument, NULL, 'k'},
201 { "ui_rotation", required_argument, NULL, 'o'},
202 { NULL, 0, NULL, 0 },
203 };
204
main(int argc,char * argv[])205 int main(int argc, char *argv[])
206 {
207 LOGI("*** update_engine: %s ***.\n", update_engine_version);
208 int arg;
209 char *image_url = NULL;
210 char *version_url = NULL;
211 char *misc_func = NULL;
212 char *save_path = NULL;
213 char *partition = NULL;
214 char *custom_define = NULL;
215 bool is_update = false;
216 bool is_reboot = false;
217 int pipefd = -1;
218
219 while ((arg = getopt_long(argc, argv, "", engine_options, NULL)) != -1) {
220 switch (arg) {
221 case 'u': is_update = true; if (optarg != NULL) is_sdboot = true; continue;
222 case 'c': version_url = optarg; continue;
223 case 'm': misc_func = optarg; continue;
224 case 'p': partition = optarg; continue;
225 case 's': save_path = optarg; continue;
226 case 'r': is_reboot = true; continue;
227 case 'v' + 'u': version_url = optarg; continue;
228 case 'i' + 'u': image_url = optarg; continue;
229 case 'p' + 'f': pipefd = atoi(optarg); continue;
230 case 'h': display(); break;
231 case 'd': custom_define = optarg; continue;
232 case 'v': LOGI("*** update_engine: %s ***.\n", update_engine_version); break;
233 case 'k': rkdebug = true; break;
234 case 'o': ui_rotation = optarg; break;
235 case '?':
236 LOGE("Invalid command argument\n");
237 continue;
238 }
239 }
240
241 if (pipefd != -1) {
242 cmd_pipe = fdopen(pipefd, "wb");
243 setlinebuf(cmd_pipe);
244 }
245
246 if (is_update) {
247 if (optarg && (strstr(optarg, "usb") != NULL || strstr(optarg, "udisk") != NULL)) {
248 is_usbboot = true;
249 is_sdboot = false;
250 LOGI("*** will upgrade firmware from udisk ***");
251 }
252
253 if (is_sdboot || is_usbboot) {
254 int res = 0x3FFC00; //默认升级的分区
255 LOGI("%s-%d: is %s update.\n", __func__, __LINE__, is_usbboot ? "usbboot" : "sdboot");
256 if (partition != NULL) {
257 res = strtol(partition + 2, NULL, 16);
258 }
259 RK_ota_set_url(image_url, save_path);
260 if ( !RK_ota_set_partition(res) ) {
261 LOGE("ota file is error.\n");
262 return -1;
263 }
264
265 if (version_url != NULL) {
266 if (!RK_ota_check_version(version_url) ) {
267 LOGE("you shouldn't update the device.\n");
268 return -1;
269 }
270 }
271
272 RK_ota_start(handle_upgrade_callback, handle_print_callback);
273 } else {
274 LOGI("%s-%d: is ota update\n", __func__, __LINE__);
275 if (MiscUpdate(image_url, partition, save_path) == 0) {
276 m_status = RK_UPGRADE_FINISHED;
277 }
278 }
279 } else if (misc_func != NULL) {
280 if (strcmp(misc_func, "now") == 0) {
281 if (setSlotSucceed() == 0) {
282 m_status = RK_UPGRADE_FINISHED;
283 }
284 } else if (strcmp(misc_func, "other") == 0) {
285 if (setSlotActivity() == 0) {
286 m_status = RK_UPGRADE_FINISHED;
287 }
288 } else if (strcmp(misc_func, "wipe_userdata") == 0) {
289 if (wipe_userdata(0) == 0) {
290 m_status = RK_UPGRADE_FINISHED;
291 }
292 } else if (strcmp(misc_func, "update") == 0) {
293 if (MiscUpdate(image_url, partition, save_path) == 0) {
294 m_status = RK_UPGRADE_FINISHED;
295 }
296 } else if (strcmp(misc_func, "display") == 0) {
297 miscDisplay();
298 } else {
299 LOGE("unknow misc cmdline : %s.\n", misc_func);
300 return 0;
301 }
302 } else if (custom_define != NULL) {
303 if (strcmp(custom_define, "read") == 0) {
304 if (readCustomMiscCmdline())
305 return -1;
306 } else if (strcmp(custom_define, "write") == 0) {
307 if (writeCustomMiscCmdline())
308 return -1;
309 } else if (strcmp(custom_define, "clean") == 0) {
310 if (cleanCustomMiscCmdline())
311 return -1;
312 } else {
313 LOGI("Not supported\n");
314 return m_status;
315 }
316 m_status = RK_UPGRADE_FINISHED;
317 }
318
319 if (is_reboot && (m_status == RK_UPGRADE_FINISHED)) {
320 sync();
321 //reboot(RB_AUTOBOOT);
322 if (system(" echo b > /proc/sysrq-trigger ") == -1)
323 return -1;
324 }
325
326 return m_status;
327 }
328