• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2020 HiSilicon (Shanghai) Technologies CO., LIMITED.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  * Description: UPG ab mode c file
15  */
16 
17 #include <stddef.h>
18 #include <stdint.h>
19 #include "errcode.h"
20 #include "common_def.h"
21 #include "sfc.h"
22 #include "partition.h"
23 #include "upg_debug.h"
24 #include "upg_porting.h"
25 #include "upg_ab.h"
26 
27 #define UPG_AB_REGION_CONFIG_SIZE 0x1000
28 #define UPG_AB_DEFAULT_REGION 0
29 #define UPG_AB_CONFIG_CHECK 0x70746C6C
30 
31 typedef struct {
32     uint32_t  check_num;    /* check number */
33     uint32_t  run_region;   /* run region */
34 } upg_ab_config_t;
35 
36 typedef struct {
37     partition_information_t  a_info;
38     partition_information_t  b_info;
39 } upg_ab_region_config_t;
40 
41 /**
42  * @brief 获取镜像分区配置参数
43  * @param region_cfg 传出的镜像分区配置参数
44  * @return 返回相关错误码
45  */
upg_get_region_config(upg_ab_region_config_t * region_cfg)46 static errcode_t upg_get_region_config(upg_ab_region_config_t *region_cfg)
47 {
48     errcode_t ret_val = ERRCODE_SUCC;
49     ret_val |= uapi_partition_get_info(PARTITION_APP_IMAGE, &(region_cfg->a_info));
50     ret_val |= uapi_partition_get_info(PARTITION_FOTA_DATA, &(region_cfg->b_info));
51     return ret_val;
52 }
53 
54 /**
55  * @brief 获取镜像分区配置的地址
56  * @param region_cfg 传出的镜像分区配置参数
57  * @return 返回相关错误码
58  */
upg_get_ab_config_addr(uint32_t * addr)59 static errcode_t upg_get_ab_config_addr(uint32_t *addr)
60 {
61     partition_information_t b_info;
62     errcode_t ret;
63 
64     ret = uapi_partition_get_info(PARTITION_FOTA_DATA, &b_info);
65     if (ret != ERRCODE_SUCC) {
66         return ERRCODE_FAIL;
67     }
68     *addr = b_info.part_info.addr_info.addr + b_info.part_info.addr_info.size - UPG_AB_REGION_CONFIG_SIZE;
69 
70     return ERRCODE_SUCC;
71 }
72 
73 /**
74  * @brief 初始化ab面升级方式的配置参数区。
75  * @param upg_cfg 需要返回的配置参数
76  * @return 返回相关错误码
77  */
upg_ab_config_init(void)78 static errcode_t upg_ab_config_init(void)
79 {
80     uint32_t upg_config_addr;
81     errcode_t ret = upg_get_ab_config_addr(&upg_config_addr);
82     if (ret != ERRCODE_SUCC) {
83         return ERRCODE_FAIL;
84     }
85 
86     upg_ab_config_t upg_cfg = {
87         .check_num = UPG_AB_CONFIG_CHECK,
88         .run_region = UPG_AB_DEFAULT_REGION,
89     };
90 
91     ret = upg_flash_erase(upg_config_addr, UPG_AB_REGION_CONFIG_SIZE);
92     ret |= upg_flash_write(upg_config_addr, sizeof(upg_ab_config_t), (const uint8_t *)(&upg_cfg), false);
93     if (ret != ERRCODE_SUCC) {
94         upg_log_err("[UPG] ab cfg init write failed, ret = 0x%x\r\n", ret);
95         return ERRCODE_UPG_FLASH_WRITE_ERROR;
96     }
97     return ERRCODE_SUCC;
98 }
99 
100 /**
101  * @brief 获取ab面升级方式的配置参数。
102  * @param upg_cfg 需要返回的配置参数
103  * @return 返回相关错误码
104  */
upg_get_ab_config(upg_ab_config_t * upg_cfg)105 static errcode_t upg_get_ab_config(upg_ab_config_t *upg_cfg)
106 {
107     uint32_t upg_config_addr;
108     errcode_t ret = upg_get_ab_config_addr(&upg_config_addr);
109     if (ret != ERRCODE_SUCC) {
110         return ERRCODE_FAIL;
111     }
112 
113     if (upg_flash_read(upg_config_addr, sizeof(upg_ab_config_t), (uint8_t *)upg_cfg) != ERRCODE_SUCC) {
114         return ERRCODE_FAIL;
115     }
116     if (upg_cfg->check_num != UPG_AB_CONFIG_CHECK) {
117         upg_log_err("[UPG] upg ab config check failed, will init, check_num = 0x%x\r\n", upg_cfg->check_num);
118         if (upg_ab_config_init() != ERRCODE_SUCC) {
119             return ERRCODE_FAIL;
120         }
121     }
122     return ERRCODE_SUCC;
123 }
124 
125 /**
126  * @brief 设置ab面升级方式的配置参数。
127  * @param upg_cfg 需要设置的配置参数
128  * @return 返回相关错误码
129  */
130 #define UPG_SET_AB_CFG_TRY_MAX 3
upg_set_ab_config(upg_ab_config_t * upg_cfg)131 static errcode_t upg_set_ab_config(upg_ab_config_t *upg_cfg)
132 {
133     upg_ab_region_config_t region_cfg = {0};
134     uint32_t try_times = 0;
135     errcode_t ret = upg_get_region_config(&region_cfg);
136     if (ret != ERRCODE_SUCC) {
137         return ERRCODE_FAIL;
138     }
139     uint32_t upg_config_addr = region_cfg.b_info.part_info.addr_info.addr + region_cfg.b_info.part_info.addr_info.size -
140         UPG_AB_REGION_CONFIG_SIZE;
141     while (try_times < UPG_SET_AB_CFG_TRY_MAX) {
142         ret = upg_flash_erase(upg_config_addr, UPG_AB_REGION_CONFIG_SIZE);
143         ret |= upg_flash_write(upg_config_addr, sizeof(upg_ab_config_t), (const uint8_t *)upg_cfg, false);
144         if (ret == ERRCODE_SUCC) {
145             break;
146         }
147         try_times++;
148     }
149     if (ret != ERRCODE_SUCC) {
150         upg_log_err("[UPG] upg set config failed, ret = 0x%x\r\n", ret);
151         return ERRCODE_UPG_FLASH_WRITE_ERROR;
152     }
153     return ERRCODE_SUCC;
154 }
155 
156 /**
157  * @brief 获取当前运行的镜像分区。
158  * @return 成功返回分区序号,失败 默认从A区启动。
159  */
upg_get_run_region(void)160 upg_region_index upg_get_run_region(void)
161 {
162     upg_ab_config_t upg_cfg = {0};
163     if (upg_get_ab_config(&upg_cfg) != ERRCODE_SUCC) {
164         return UPG_AB_DEFAULT_REGION;
165     }
166     if (upg_cfg.run_region != UPG_REGION_A && upg_cfg.run_region != UPG_REGION_B) {
167         return UPG_AB_DEFAULT_REGION;
168     }
169     return upg_cfg.run_region;
170 }
171 
172 /**
173  * @brief 获取待升级的镜像分区。
174  * @return 返回分区序号。
175  */
upg_get_upg_region(void)176 upg_region_index upg_get_upg_region(void)
177 {
178     if (upg_get_run_region() == UPG_REGION_B) {
179         return UPG_REGION_A;
180     } else {
181         return UPG_REGION_B;
182     }
183 }
184 
185 /**
186  * @brief 获取镜像分区的起始地址。
187  * @param upg_region 需要获取的镜像分区
188  * @return 成功返回分区地址,失败返回 0
189  */
190 #define UPG_SIZE_4K_ALIGN 4095
191 #define UPG_SIZE_4K (UPG_SIZE_4K_ALIGN + 1)
upg_get_region_addr(upg_region_index upg_region)192 uint32_t upg_get_region_addr(upg_region_index upg_region)
193 {
194     upg_ab_region_config_t info = {0};
195     if (upg_get_region_config(&info) != ERRCODE_SUCC) {
196         upg_log_err("[UPG] upg get region addr failed\r\n");
197         return 0;
198     }
199     uint32_t image_addr = info.a_info.part_info.addr_info.addr;
200     uint32_t all_size = info.a_info.part_info.addr_info.size + info.b_info.part_info.addr_info.size;
201     uint32_t single_size = (all_size - UPG_AB_REGION_CONFIG_SIZE) / UPG_REGION_COUNT;
202     single_size = (single_size + UPG_SIZE_4K_ALIGN) & ~(UPG_SIZE_4K_ALIGN);
203     switch (upg_region) {
204         case UPG_REGION_A:
205             return image_addr;
206         case UPG_REGION_B:
207             return image_addr + single_size;
208         default:
209             return 0;
210     }
211 }
212 
213 /**
214  * @brief 获取镜像分区的大小。
215  * @param upg_region 需要获取的镜像分区
216  * @return 成功返回分区大小,失败返回 0
217  */
upg_get_region_size(upg_region_index upg_region)218 uint32_t upg_get_region_size(upg_region_index upg_region)
219 {
220     unused(upg_region);
221     upg_ab_region_config_t info = {0};
222     if (upg_get_region_config(&info) != ERRCODE_SUCC) {
223         return 0;
224     }
225     uint32_t all_size = info.a_info.part_info.addr_info.size + info.b_info.part_info.addr_info.size;
226     uint32_t single_size = (all_size - UPG_AB_REGION_CONFIG_SIZE) / UPG_REGION_COUNT;
227     single_size = (single_size + UPG_SIZE_4K_ALIGN) & ~(UPG_SIZE_4K_ALIGN);
228     switch (upg_region) {
229         case UPG_REGION_A:
230             return single_size;
231         case UPG_REGION_B:
232             return all_size - UPG_AB_REGION_CONFIG_SIZE - single_size;
233         default:
234             return 0;
235     }
236 }
237 
238 /**
239  * @brief 读取镜像数据。
240  * @param upg_region,镜像区域,UPG_REGION_XXX。
241  * @param offset 偏移量。
242  * @param buf 内存指针。
243  * @param len 读取的长度。
244  * @return 成功返回ERRCODE_SUCC,失败返回错误码。
245  */
upg_ab_image_read(upg_region_index upg_region,uint32_t offset,uint8_t * buf,size_t len)246 uint32_t upg_ab_image_read(upg_region_index upg_region, uint32_t offset, uint8_t *buf, size_t len)
247 {
248     uint32_t addr = upg_get_region_addr(upg_region);
249     uint32_t size = upg_get_region_size(upg_region);
250     if (addr == 0 || size == 0 || (offset + len) > size) {
251         return ERRCODE_INVALID_PARAM;
252     }
253     return upg_flash_read(addr + offset, len, buf);
254 }
255 
256 /**
257  * @brief 写入镜像数据。
258  * @param upg_region,镜像区域,UPG_REGION_XXX。
259  * @param offset 偏移量。
260  * @param buf 待写入数据的内存指针。
261  * @param len 写入的长度。
262  * @return 成功返回ERRCODE_SUCC,失败返回错误码。
263  */
upg_ab_image_write(upg_region_index upg_region,uint32_t offset,uint8_t * buf,size_t len)264 uint32_t upg_ab_image_write(upg_region_index upg_region, uint32_t offset, uint8_t *buf, size_t len)
265 {
266     uint32_t addr = upg_get_region_addr(upg_region);
267     uint32_t size = upg_get_region_size(upg_region);
268     if (addr == 0 || size == 0 || (offset + len) > size) {
269         return ERRCODE_INVALID_PARAM;
270     }
271     /* false: start过程已擦除整个待升级镜像区,此处不需写前擦 */
272     return upg_flash_write(addr + offset, len, buf, false);
273 }
274 
275 /**
276  * @brief 镜像版本切换
277  * @param upg_region 镜像区域,UPG_REGION_A/UPG_REGION_B。下一次启动的版本区域是upg_region。
278  * @return 成功返回ERRCODE_SUCC,失败返回错误码。
279  */
upg_set_run_region(upg_region_index upg_region)280 errcode_t upg_set_run_region(upg_region_index upg_region)
281 {
282     upg_ab_config_t upg_cfg = {0};
283     errcode_t ret = upg_get_ab_config(&upg_cfg);
284     if (ret != ERRCODE_SUCC) {
285         return ret;
286     }
287     if (upg_cfg.run_region == upg_region) {
288         upg_log_err("[UPG] set the same region with the current,please check\r\n");
289         return ERRCODE_INVALID_PARAM;
290     }
291     upg_cfg.run_region = upg_region;
292     ret = upg_set_ab_config(&upg_cfg);
293     if (ret != ERRCODE_SUCC) {
294         upg_log_err("[UPG] set the config failed\r\n");
295         return ret;
296     }
297     return ERRCODE_SUCC;
298 }
299 
300 /**
301  * @brief 擦除待升级的镜像区
302  * @param region 待擦除的镜像区域,UPG_REGION_A/UPG_REGION_B303  * @return 成功返回ERRCODE_SUCC,失败返回错误码。
304  */
upg_region_erase(upg_region_index region)305 errcode_t upg_region_erase(upg_region_index region)
306 {
307     uint32_t addr = upg_get_region_addr(region);
308     uint32_t size = upg_get_region_size(region);
309     upg_log_info("[UPG] erase region addr:0x%08x, size:0x%08x\r\n", addr, size);
310 
311     if ((addr & UPG_SIZE_4K_ALIGN) || (size % UPG_SIZE_4K)) {
312         upg_log_err("[UPG] region addr:0x%08x or size:0x%08x is not 4K aligned\r\n", addr, size);
313         return ERRCODE_INVALID_PARAM;
314     }
315     if (uapi_sfc_reg_erase(addr, size) != ERRCODE_SUCC) {
316         upg_log_err("[UPG] erase region failed\r\n");
317         return ERRCODE_FAIL;
318     }
319     return ERRCODE_SUCC;
320 }
321 
322 /**
323  * @brief 镜像升级开始,准备写入镜像
324  * @param upg_region 镜像区域,UPG_REGION_A/UPG_REGION_B
325  * @return 成功返回ERRCODE_SUCC,失败返回错误码。
326  */
upg_ab_start(upg_region_index upg_region)327 errcode_t upg_ab_start(upg_region_index upg_region)
328 {
329     if (upg_region == UPG_REGION_A || upg_region == UPG_REGION_B) {
330         return ERRCODE_INVALID_PARAM;
331     }
332 
333     if (ws63_upg_init() != ERRCODE_SUCC) {
334         return ERRCODE_FAIL;
335     }
336     return upg_region_erase(upg_get_upg_region());
337 }
338