1 #include <string.h>
2 #include "ota_port.h"
3 #include "hal_trace.h"
4 #include "hal_norflash.h"
5 #include "cmsis_os.h"
6 #include "cmsis.h"
7 #include "pmu.h"
8 #include "aos/hal/flash.h"
9 #include "aos/mtd.h"
10 #include <vfsdev/flash_dev.h>
11 #include "aos/mtdpart.h"
12 
13 extern const hal_logic_partition_t hal_partitions[];
14 extern osMutexId FlashMutex;
15 extern osMutexDef_t os_mutex_def_flash;
16 extern enum ota_link ota_current_link;
17 
18 #define EXCEPTION_REBOOT_COUNT_MAX		5
19 
20 ota_bin_partition ota_bin[] =
21 {
22     {"ota_boot2a.bin",  HAL_PARTITION_BOOT1},
23     {"ota_boot2b.bin",  HAL_PARTITION_BOOT1_REDUND},
24     {"ota_rtos.bin",    HAL_PARTITION_APPLICATION},
25     {"littlefs.bin",    HAL_PARTITION_LITTLEFS},
26 };
27 
FlashosMutexWait(void)28 static void FlashosMutexWait(void)
29 {
30     if(FlashMutex == NULL)
31     {
32         FlashMutex = osMutexCreate(&os_mutex_def_flash);
33     }
34 
35     osMutexWait(FlashMutex, osWaitForever);
36 }
37 
ota_get_bootinfo(struct ota_boot_info * info,enum bootinfo_zone zone)38 int ota_get_bootinfo(struct ota_boot_info *info, enum bootinfo_zone zone)
39 {
40     uint32_t lock = 0;
41     uint32_t start_addr = 0;
42     mtd_partition_t* partition_info;
43     volatile char *flashPointer = NULL;
44 
45     if (zone >= OTA_BOOTINFO_ZONEMAX) {
46         TRACE("error %s %d, zone:%d", __func__, __LINE__, zone);
47         return OTA_FAILE;
48     }
49     partition_info = (mtd_partition_t *)&mtd_partitions[MTD_PART_ID_ENV2];
50     if(partition_info == NULL) {
51         return OTA_FAILE;
52     }
53     if (zone == OTA_BOOTINFO_ZONEA) {
54         start_addr = partition_info->partition_start_addr;
55     } else if (zone == OTA_BOOTINFO_ZONEB) {
56         start_addr = partition_info->partition_start_addr + OTA_BOOT_INFO_SIZE;
57     }
58 
59     lock = int_lock();
60     flashPointer = (volatile char *)(FLASH_NC_BASE + start_addr);
61     memcpy((uint8_t*)info, (void *)flashPointer, sizeof(struct ota_boot_info));
62     int_unlock(lock);
63 
64     return 0;
65 }
66 
ota_set_bootinfo_crc32value(struct ota_boot_info * info)67 int ota_set_bootinfo_crc32value(struct ota_boot_info *info)
68 {
69     uint32_t crc32_value = 0;
70     uint8_t *flash_pointer = NULL;
71 
72     flash_pointer = (uint8_t *)(info);
73     crc32_value = crc32(crc32_value, (uint8_t *)(flash_pointer + OTA_BOOT_INFO_HEAD_LEN), info->info_len);
74     info->crc32 = crc32_value;
75 
76     return 0;
77 }
78 
ota_set_bootinfo(struct ota_boot_info * info,enum bootinfo_zone zone)79 int ota_set_bootinfo(struct ota_boot_info *info, enum bootinfo_zone zone)
80 {
81     int ret = 0;
82     uint32_t lock = 0;
83     uint32_t start_addr = 0;
84     uint8_t buffer[FLASH_SECTOR_SIZE_IN_BYTES] = {0};
85     mtd_partition_t* partition_info = NULL;
86 
87     if (zone >= OTA_BOOTINFO_ZONEMAX) {
88         TRACE("error %s %d, zone:%d", __func__, __LINE__, zone);
89         return OTA_FAILE;
90     }
91 
92     ret = ota_set_bootinfo_crc32value(info);
93     if (ret) {
94         return OTA_FAILE;
95     }
96     partition_info = (mtd_partition_t *)&mtd_partitions[MTD_PART_ID_ENV2];
97     if(partition_info == NULL) {
98         return OTA_FAILE;
99     }
100     if (zone == OTA_BOOTINFO_ZONEA) {
101         start_addr = partition_info->partition_start_addr;
102     } else if (zone == OTA_BOOTINFO_ZONEB) {
103         start_addr = partition_info->partition_start_addr + OTA_BOOT_INFO_SIZE;
104     }
105 
106     lock = int_lock();
107     pmu_flash_write_config();
108 
109     memcpy(buffer, (uint8_t *)info, sizeof(struct ota_boot_info));
110     ret = hal_norflash_erase(HAL_NORFLASH_ID_0, start_addr, FLASH_SECTOR_SIZE_IN_BYTES);
111     if (ret != HAL_NORFLASH_OK) {
112         TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
113         goto end;
114     }
115 
116     ret = hal_norflash_write(HAL_NORFLASH_ID_0, start_addr, buffer, FLASH_SECTOR_SIZE_IN_BYTES);
117     if (ret != HAL_NORFLASH_OK) {
118         TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
119         goto end;
120     }
121 
122 end:
123     pmu_flash_read_config();
124     int_unlock(lock);
125 
126     return ret;
127 }
128 
ota_set_bootinfo_to_zoneAB(struct ota_boot_info * info)129 int ota_set_bootinfo_to_zoneAB(struct ota_boot_info *info)
130 {
131     int ret = 0;
132 
133     ret = ota_set_bootinfo(info, OTA_BOOTINFO_ZONEA);
134     if (ret) {
135         TRACE("error %s %d, ota_set_bootinfo return %d", __func__, __LINE__, ret);
136     }
137 
138     ret = ota_set_bootinfo(info, OTA_BOOTINFO_ZONEB);
139     if (ret) {
140         TRACE("error %s %d, ota_set_bootinfo return %d", __func__, __LINE__, ret);
141     }
142 
143     return ret;
144 }
145 
ota_check_bootinfo(enum bootinfo_zone zone)146 int ota_check_bootinfo(enum bootinfo_zone zone)
147 {
148     uint32_t crc32_value = 0;
149     uint32_t flash_offset = 0;
150     uint8_t *flash_pointer = NULL;
151     mtd_partition_t *partition_info = NULL;
152     const struct ota_boot_info *info;
153 
154     if (zone >= OTA_BOOTINFO_ZONEMAX) {
155         TRACE("%s %d, error zone:%d", __func__, __LINE__, zone);
156         return OTA_FAILE;
157     }
158     partition_info = (mtd_partition_t *)&mtd_partitions[MTD_PART_ID_ENV2];
159     if(partition_info == NULL) {
160         return OTA_FAILE;
161     }
162 
163     //get boot info to choose linkA or linkB.
164     if (zone == OTA_BOOTINFO_ZONEA) {
165         flash_offset = partition_info->partition_start_addr;
166     } else if (zone == OTA_BOOTINFO_ZONEB) {
167         flash_offset = partition_info->partition_start_addr + OTA_BOOT_INFO_SIZE; //boot info zoneB start address
168     }
169 
170     info = (const struct ota_boot_info *)(FLASH_NC_BASE + flash_offset);
171     if (info->update_link >= OTA_LINK_MAX) {
172         TRACE("%s %d, error info->update_link:%d", __func__, __LINE__, info->update_link);
173         return OTA_FAILE;
174     } else if ((info->update_link == OTA_LINK_A) && (info->linkA_used_flag != OTA_LINK_USED)) {
175         TRACE("%s %d, error info->linkA_used_flag:%d", __func__, __LINE__, info->linkA_used_flag);
176         return OTA_FAILE;
177     } else if ((info->update_link == OTA_LINK_B) && (info->linkB_used_flag != OTA_LINK_USED)) {
178         TRACE("%s %d, error info->linkB_used_flag:%d", __func__, __LINE__, info->linkB_used_flag);
179         return OTA_FAILE;
180     }
181 
182     flash_pointer = (uint8_t *)(info);
183     crc32_value = crc32(crc32_value, (uint8_t *)(flash_pointer + OTA_BOOT_INFO_HEAD_LEN), info->info_len);
184     if (crc32_value != info->crc32) {
185         TRACE("%s %d, error info->crc32:0x%x, crc32_value:0x%x", __func__, __LINE__, info->crc32, crc32_value);
186         return OTA_FAILE;
187     }
188 
189     return OTA_OK;
190 }
191 
ota_set_zoneAB_bootinfo_to_default(void)192 void ota_set_zoneAB_bootinfo_to_default(void)
193 {
194     struct ota_boot_info info;
195     int ret = 0;
196 
197     TRACE("%s %d", __func__, __LINE__);
198 
199     //set boot info to A and B.
200     memset(&info, 0, sizeof(struct ota_boot_info));
201     info.linkA_used_flag  		 = OTA_LINK_USED;
202     info.linkB_used_flag  		 = OTA_LINK_USED; //if RTOSB not write, set OTA_LINK_NOTUSED.
203     info.info_len         		 = OTA_BOOT_INFO_BODY_LEN;
204 	info.odm_type         		 = 0;
205 	info.reserved         		 = 0;
206     info.update_link      		 = OTA_LINK_A; //default:OTA_LINK_A
207     info.reboot_reason           = 0;
208     info.crash_reboot_count      = 0;
209 	info.secureERR_reboot_count  = 0;
210     info.reboot_count_max 		 = EXCEPTION_REBOOT_COUNT_MAX;
211     info.fallback_disable 		 = 1;
212 
213     ret = ota_set_bootinfo_to_zoneAB(&info);
214     if (ret) {
215         TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
216         return;
217     }
218 }
219 
ota_get_valid_bootinfo_zone(void)220 enum bootinfo_zone ota_get_valid_bootinfo_zone(void)
221 {
222     enum bootinfo_zone ret = OTA_BOOTINFO_ZONEA;
223 
224     //get boot info to choose linkA or linkB.
225     ret = ota_check_bootinfo(OTA_BOOTINFO_ZONEA);
226     if (!ret) {
227         return OTA_BOOTINFO_ZONEA;
228     } else {
229         ret = ota_check_bootinfo(OTA_BOOTINFO_ZONEB);
230         if (!ret) {
231             return OTA_BOOTINFO_ZONEB;
232         } else { //first boot or both boot info bad, set both to default.
233             ota_set_zoneAB_bootinfo_to_default();
234             return OTA_BOOTINFO_ZONEA;
235         }
236     }
237 }
238 
ota_adapt_get_odm_type(void)239 ODM_TYPE ota_adapt_get_odm_type(void)
240 {
241     int32_t ret = 0;
242     struct ota_boot_info boot_info;
243     enum bootinfo_zone zone;
244 
245     zone = ota_get_valid_bootinfo_zone();
246     ret = ota_get_bootinfo(&boot_info, zone);
247     if (ret) {
248 		TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
249         return ALI_ODM_MAX;
250     }
251 
252     return boot_info.odm_type;
253 }
254 
ota_adapt_set_odm_type(ODM_TYPE type)255 int ota_adapt_set_odm_type(ODM_TYPE type)
256 {
257     int32_t ret = 0;
258     struct ota_boot_info boot_info;
259 	enum bootinfo_zone zone;
260 
261 	if (type >= ALI_ODM_MAX) {
262 		return -1;
263 	}
264 
265 	zone = ota_get_valid_bootinfo_zone();
266     ret = ota_get_bootinfo(&boot_info, zone);
267     if (ret) {
268 		TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
269         return ret;
270     }
271 
272     boot_info.odm_type = type;
273 	ret = ota_set_bootinfo_to_zoneAB(&boot_info);
274     if (ret) {
275         TRACE("error %s %d, ret:%d", __func__, __LINE__, ret);
276     }
277 
278 	return ret;
279 }
280 
ota_copy_bootinfo_fromone_toanother(enum bootinfo_zone to_zone,enum bootinfo_zone from_zone)281 int ota_copy_bootinfo_fromone_toanother(enum bootinfo_zone to_zone, enum bootinfo_zone from_zone)
282 {
283     struct ota_boot_info info;
284     int32_t ret = 0;
285 
286     if ((to_zone >= OTA_BOOTINFO_ZONEMAX) || (from_zone >= OTA_BOOTINFO_ZONEMAX)) {
287         //TRACE("%s %d, error zone:%d", __func__, __LINE__, zone);
288         return -1;
289     }
290 
291     //get boot info from from_zone.
292     ret = ota_get_bootinfo(&info, from_zone);
293     if (ret) {
294         TRACE("%s %d, ota_get_bootinfo return fail", __func__, __LINE__);
295         return -1;
296     }
297 
298     //set boot info to to_zone.
299     ret = ota_set_bootinfo(&info, to_zone);
300     if (ret) {
301         TRACE("%s %d, ota_get_bootinfo return fail", __func__, __LINE__);
302         return -1;
303     }
304 
305     return ret;
306 }
307 
308 /**
309  * @brief Get current active A/B slot
310  *
311  * @returns "a" if current slot is A, or "b" if current slot is B.
312  */
tg_ota_get_current_ab(void)313 const char* tg_ota_get_current_ab(void)
314 {
315     int32_t ret = 0;
316     struct ota_boot_info boot_info;
317     enum bootinfo_zone zone;
318 
319     zone = ota_get_valid_bootinfo_zone();
320     ret = ota_get_bootinfo(&boot_info, zone);
321     if (ret) {
322         return NULL;
323     }
324 
325     if (boot_info.update_link == OTA_LINK_A) {
326         return "a";
327     } else if (boot_info.update_link == OTA_LINK_B) {
328         return "b";
329     }
330     return NULL;
331 }
332 
333 /**
334  * @return: - 0: success; - -1: fail
335  */
ota_upgrade_link()336 int ota_upgrade_link()
337 {
338     int32_t ret = -1;
339     struct ota_boot_info info;
340 	enum bootinfo_zone zone;
341 
342 	if (ota_current_link == OTA_LINK_ERR) {
343 		zone = ota_get_valid_bootinfo_zone();
344 	    ret = ota_get_bootinfo(&info, zone);
345         if (ret != 0) {
346             return -1;
347 	    }
348 		ota_current_link = info.update_link;
349 	}
350 
351     if ((ota_current_link == OTA_LINK_A) || (ota_current_link == OTA_LINK_B)) {
352 		zone = ota_get_valid_bootinfo_zone();
353 	    ret = ota_get_bootinfo(&info, zone);
354         if (ret != 0) {
355             return -1;
356         }
357 
358 	    if (ota_current_link == OTA_LINK_B) {
359 	        info.linkA_used_flag = OTA_LINK_USED;
360 			info.update_link = OTA_LINK_A;
361 	    } if (ota_current_link == OTA_LINK_A) {
362 	        info.linkB_used_flag = OTA_LINK_USED;
363 			info.update_link = OTA_LINK_B;
364 	    }
365 
366 		info.crash_reboot_count = 0; //reset to 0
367 		info.secureERR_reboot_count = 0; //reset to 0
368 		info.reboot_reason = 0;
369 		info.fallback_disable = 0; //enable fallback
370 
371 	    ret = ota_set_bootinfo_to_zoneAB(&info); //sync bootinfo A with B
372 	    if (ret) {
373 			TRACE("error %s %d, return:%d", __func__, __LINE__, ret);
374             return -1;
375 	    } else {
376 			ota_current_link = info.update_link;
377         }
378 		TRACE("%s %d, ota_current_link:%d, zone:%d", __func__, __LINE__, ota_current_link, zone);
379     }
380 
381     return ret;
382 }
383 
ota_clear_reboot_count(void)384 int ota_clear_reboot_count(void)
385 {
386     int32_t ret = 0;
387     struct ota_boot_info info;
388 	enum bootinfo_zone zone;
389 
390     zone = ota_get_valid_bootinfo_zone();
391     ret = ota_get_bootinfo(&info, zone);
392     if (ret) {
393         return OTA_FAILE;
394     }
395 
396 	if ((info.crash_reboot_count != 0) ||(info.secureERR_reboot_count != 0) ) {
397 	    info.crash_reboot_count = 0; //reset to 0
398 	    info.secureERR_reboot_count = 0; //reset to 0
399 	    info.reboot_reason = 0;
400 	    info.fallback_disable = 0; //enable fallback
401 
402 	    ret = ota_set_bootinfo_to_zoneAB(&info); //sync bootinfo A with B
403 	    if (ret) {
404 			TRACE("error %s %d, return:%d", __func__, __LINE__, ret);
405             return ret;
406 	    }
407 	}
408 
409     return ret;
410 }
411 
ota_get_boot_type()412 int ota_get_boot_type()
413 {
414     int boot_type = 1;
415     return boot_type;
416 }
417 
ota_set_user_bootinfo(void * param)418 int ota_set_user_bootinfo(void *param)
419 {
420     (void *)param;
421     return ota_upgrade_link();
422 }
423 
ota_hal_rollback_platform_hook(void)424 int ota_hal_rollback_platform_hook(void)
425 {
426      return ota_clear_reboot_count();
427 }
428 
ota_hal_platform_boot_type(void)429 int ota_hal_platform_boot_type(void)
430 {
431     return ota_get_boot_type();
432 }
433 
ota_get_running_index(void)434 int ota_get_running_index(void)
435 {
436     int32_t ret = 0;
437     struct ota_boot_info info;
438     enum bootinfo_zone zone;
439 
440     zone = ota_get_valid_bootinfo_zone();
441     ret = ota_get_bootinfo(&info, zone);
442     if (ret) {
443         printf("%s err \r\n", __FUNCTION__);
444         return -1;
445     }
446     return info.update_link;
447 }
448 
ota_hal_final(void)449 int ota_hal_final(void)
450 {
451     return ota_set_user_bootinfo(NULL);
452 }
453