1 
2 /*
3  * Copyright (C) 2015-2017 Alibaba Group Holding Limited
4  */
5 #include "2ndboot.h"
6 
7 #define YMODEM_OK          0
8 #define YMODEM_ERR         (-1)
9 #define YMODEM_FILE_TOOBIG (-2)
10 
11 #define YMODEM_SOH 0x01
12 #define YMODEM_STX 0x02
13 #define YMODEM_EOT 0x04
14 #define YMODEM_ACK 0x06
15 #define YMODEM_NAK 0x15
16 #define YMODEM_CAN 0x18
17 #define YMODEM_CCHAR 'C'
18 #define SOH_DATA_LEN 128
19 #define STX_DATA_LEN 1024
20 
21 #define UART_RECV_TIMEOUT 400000
22 
23 #define YMODEM_STATE_INIT      0
24 #define YMODEM_STATE_WAIT_HEAD 1
25 #define YMODEM_STATE_WAIT_DATA 2
26 #define YMODEM_STATE_WAIT_END  3
27 #define YMODEM_STATE_WAIT_NEXT 4
28 
29 #define YMODEM_MAX_CHAR_NUM    64
30 #define YMODEM_ERR_NAK_NUM     5
31 
32 static unsigned int ymodem_flash_addr     = 0;
33 static unsigned int ymodem_flash_size     = 0;
34 static unsigned int ymodem_max_write_size = 0;
35 
ymodem_str2int(char * buf,unsigned int buf_len)36 unsigned int ymodem_str2int(char *buf, unsigned int buf_len)
37 {
38     int type  = 10;
39     int value = 0;
40     int i     = 0;
41 
42     if((buf[0] == '0') && (buf[1] == 'x' || buf[1] == 'X')) {
43         type = 16;
44         buf += 2;
45     }
46     for (i = 0; i < buf_len; buf++, i++) {
47         if(*buf == 0) {
48             return value;
49         }
50         if (*buf >= '0' && *buf <= '9') {
51             value = value * type + *buf - '0';
52         } else {
53             if(10 == type) {
54                 return value;
55             }
56             if (*buf >= 'A' && *buf <= 'F') {
57                 value = value * 16 + *buf - 'A' + 10;
58             }
59             else if (*buf >= 'a' && *buf <= 'f') {
60                 value = value * 16 + *buf - 'a' + 10;
61             } else {
62                 return value;
63             }
64         }
65     }
66     return value;
67 }
68 
ymodem_recv_bytes(unsigned char * buffer,unsigned int nbytes,unsigned int timeout)69 unsigned int ymodem_recv_bytes(unsigned char *buffer, unsigned int nbytes, unsigned int timeout)
70 {
71     int ret = 0;
72     unsigned char c = 0;
73     unsigned int  i = 0;
74     unsigned int  t = 0;
75 
76     while ((i < nbytes) && (t < timeout)) {
77         ret = uart_recv_byte(&c);
78         if (1 == ret) {
79             buffer[i] = c;
80             i++;
81         }
82         t++;
83     }
84     return i;
85 }
86 
ymodem_data_head_parse(unsigned char data_type)87 int ymodem_data_head_parse(unsigned char data_type)
88 {
89     int    i   = 0;
90     int    ret = YMODEM_ERR;
91     int    lp  = 0;
92     unsigned int buf_len = 0;
93     unsigned char *buffer = NULL;
94     unsigned short crc    = 0;
95     unsigned int   value  = 0;
96 
97     buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
98     buffer  = malloc(buf_len);
99     memset(buffer, 0, buf_len);
100     /* SOH HEAD */
101     value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT);
102     if( (buf_len != value)  || (0 != buffer[0]) || (0xFF != buffer[1]) ) {
103         goto err_exit;
104     }
105 
106     /* check CRC */
107     crc = crc16_computer(&buffer[2], buf_len-4);
108     if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
109         goto err_exit;
110     }
111     /* parse file name && file length */
112     for(i = 2; i < buf_len - 2; i++) {
113         if((0 == buffer[i]) && (0 == lp)) {
114             lp = i + 1;
115             continue;
116         }
117 
118         if((0 == buffer[i]) && (0 != lp)) {
119             /* from buffer[lp] to buffer[i] is file length ascii */
120             value = ymodem_str2int((char *)&buffer[lp], i - lp);
121             if (0 == value) {
122                 goto err_exit;
123             }
124             ymodem_flash_size = value;
125             if(value > ymodem_max_write_size) {
126                 ret = YMODEM_FILE_TOOBIG;
127                 goto err_exit;
128             }
129             #ifdef AOS_2ND_BOOT_LATER_ERASE
130             flash_erase(ymodem_flash_addr, ymodem_flash_size);
131             #endif
132             break;
133         }
134     }
135 
136     for (i = 2; i < buf_len - 4; i ++) {
137         if (buffer[i] != 0) {
138             ret = YMODEM_OK;
139         }
140     }
141 
142 err_exit:
143     free(buffer);
144     return ret;
145 }
146 
ymodem_write_data_to_flash(unsigned char * buffer,unsigned int addr,unsigned int len)147 int ymodem_write_data_to_flash(unsigned char *buffer, unsigned int addr, unsigned int len)
148 {
149     unsigned int write_len = len;
150     if(addr + len > ymodem_flash_addr + ymodem_flash_size) {
151         write_len = ymodem_flash_addr + ymodem_flash_size - addr;
152     }
153     return flash_write_data(addr, buffer, write_len);
154 }
155 
ymodem_data_parse(unsigned char data_type,unsigned int * addr)156 int ymodem_data_parse(unsigned char data_type, unsigned int *addr)
157 {
158     int ret = YMODEM_ERR;
159     unsigned int buf_len = 0;
160     unsigned short crc    = 0;
161     unsigned int   value  = 0;
162     unsigned char *buffer = NULL;
163 
164     buf_len = ((YMODEM_SOH == data_type) ? SOH_DATA_LEN : STX_DATA_LEN) + 4;
165     buffer = malloc(buf_len);
166     memset(buffer, 0, buf_len);
167 
168     if(NULL == addr) {
169         goto err_exit;
170     }
171     /* SOH HEAD */
172     value = ymodem_recv_bytes(buffer, buf_len, UART_RECV_TIMEOUT * (buf_len / SOH_DATA_LEN));
173     if ((buf_len != value) || (0xFF != buffer[0] + buffer[1])) {
174         goto err_exit;
175     }
176 
177     /* check CRC */
178     crc = crc16_computer(&buffer[2], buf_len - 4);
179     if (((crc >> 8) != buffer[buf_len - 2]) || ((crc & 0xFF) != buffer[buf_len - 1])) {
180         goto err_exit;
181     }
182 
183     /* write data fo flash */
184     ymodem_write_data_to_flash(&buffer[2], *addr, buf_len - 4);
185     *addr += buf_len - 4;
186     ret = YMODEM_OK;
187 
188 err_exit :
189     free(buffer);
190     return ret;
191 }
192 
ymodem_recv_file(unsigned int flash_addr)193 int ymodem_recv_file(unsigned int flash_addr)
194 {
195     int i        = 0;
196     int ret      = YMODEM_OK;
197     int state    = 0;
198     int end_flag = 0;
199     unsigned char c     = 0;
200     unsigned int  bytes = 0;
201     unsigned int  addr  = flash_addr;
202 
203     /* send C */
204     while (1) {
205         if(state != YMODEM_STATE_INIT) {
206             bytes = ymodem_recv_bytes(&c, 1, 5000);
207         }
208 
209         switch (state)
210         {
211         case YMODEM_STATE_INIT: /* send 'C' */
212             if(i % 500 == 0) {
213                 uart_send_byte(YMODEM_CCHAR);
214             }
215             state = YMODEM_STATE_WAIT_HEAD;
216             break;
217 
218         case YMODEM_STATE_WAIT_HEAD: /* wait SOH */
219             if(1 != bytes) {
220                 i ++;
221                 state = 0;
222                 break;
223             }
224             if(( YMODEM_SOH == c ) || ( YMODEM_STX == c )) {
225                 ret = ymodem_data_head_parse(c);
226                 if (ret == YMODEM_OK) {
227                     uart_send_byte(YMODEM_ACK);
228                     sys_delayms(100);
229                     uart_send_byte(YMODEM_CCHAR);
230                     state = YMODEM_STATE_WAIT_DATA;
231                     break;
232                 } else {
233                     /* end */
234                     uart_send_byte(YMODEM_ACK);
235                     sys_delayms(200);
236                     if(end_flag == 1) {
237                         ret = YMODEM_OK;
238                     } else {
239                         for(i = 0; i < YMODEM_ERR_NAK_NUM; i++) {
240                             uart_send_byte(YMODEM_NAK);
241                         }
242                     }
243                     return ret;
244                 }
245             } else if (3 == c) {  /* ctrl+c abort ymodem */
246                 printf("Abort\n");
247                 return YMODEM_ERR;
248             }
249             break;
250         case YMODEM_STATE_WAIT_DATA: /* receive data */
251             if(1 == bytes) {
252                 if( (YMODEM_SOH == c) || (YMODEM_STX == c) ) {
253                     ret = ymodem_data_parse(c, &addr);
254                     if (ret == YMODEM_OK) {
255                         uart_send_byte(YMODEM_ACK);
256                     } else {
257                         uart_send_byte(YMODEM_NAK);
258                     }
259                 } else if( YMODEM_EOT == c ) {
260                     uart_send_byte(YMODEM_NAK);
261                     state = YMODEM_STATE_WAIT_END;
262                 }
263             }
264             break;
265         case YMODEM_STATE_WAIT_END: /* receive end eot */
266             if ((1 == bytes) && (YMODEM_EOT == c)) {
267                 uart_send_byte(YMODEM_ACK);
268                 i     = 0;
269                 state = YMODEM_STATE_INIT;
270                 end_flag = 1;
271             }
272             break;
273         default:
274             state = YMODEM_STATE_INIT;
275             break;
276         }
277     }
278 
279     return YMODEM_OK;
280 }
281 
ymodem_upgrade(void)282 int ymodem_upgrade(void)
283 {
284     int    i = 0;
285     int  ret = 0;
286     int flag = 0;
287     unsigned char c   = 0;
288     unsigned int addr = 0;
289     char buf[YMODEM_MAX_CHAR_NUM];
290     hal_logic_partition_t *app_info = flash_get_info(HAL_PARTITION_APPLICATION);
291     hal_logic_partition_t *ota_info = flash_get_info(HAL_PARTITION_OTA_TEMP);
292     if((app_info == NULL) || (ota_info == NULL)) {
293         printf("\r\nGet Flash info err !\n");
294         return -1;
295     }
296 #ifdef AOS_2ND_BOOT_AB
297     printf("\r\nA part addr:0x%08x, len:0x%08x\n", app_info->partition_start_addr,
298             app_info->partition_length);
299     printf("\r\nB part addr:0x%08x, len:0x%08x\n", ota_info->partition_start_addr,
300             ota_info->partition_length);
301 
302     printf("\r\nNow running on %s\n", (ota_2ndboot_ab_get() == 0)?"A":"B");
303     printf("\r\nBackup part addr:0x%08x\n", (ota_2ndboot_ab_get() == 0)?ota_info->partition_start_addr:app_info->partition_start_addr);
304 #else
305     printf("\r\nOS  part addr:0x%08x, len:0x%08x\n", app_info->partition_start_addr,
306             app_info->partition_length);
307     printf("\r\nOTA part addr:0x%08x, len:0x%08x\n", ota_info->partition_start_addr,
308             ota_info->partition_length);
309     printf("\r\nOnly the addr of OS and OTA part are allowed to be written\n");
310 #endif
311     printf("\r\nPlease input flash addr: ");
312     memset(buf, 0, YMODEM_MAX_CHAR_NUM);
313     while(1) {
314         if(uart_recv_byte(&c)&&(c!='w')) {
315             printf("%c", c);
316             if((c == '\r') || (i >= YMODEM_MAX_CHAR_NUM)) {
317                 break;
318             }
319             buf[i] = c;
320             i ++;
321         }
322     }
323     printf("\r\nflash addr: %s \n", buf);
324     addr = ymodem_str2int(buf, YMODEM_MAX_CHAR_NUM);
325     if(addr == 0) {
326         printf("\r\naddr is invalid!\n");
327         return -1;
328     }
329     if((addr >= app_info->partition_start_addr) && (addr <= app_info->partition_start_addr + app_info->partition_length)) {
330         flag = 1;
331         ymodem_max_write_size = app_info->partition_length;
332         #ifndef AOS_2ND_BOOT_LATER_ERASE
333         ret = flash_erase(app_info->partition_start_addr, app_info->partition_length);
334         if(ret < 0) {
335             printf("erase err.\n");
336             return -1;
337         }
338         #endif
339     }
340     if((addr >= ota_info->partition_start_addr) && (addr <= ota_info->partition_start_addr + ota_info->partition_length)){
341         flag = 1;
342         ymodem_max_write_size = ota_info->partition_length;
343         #ifndef AOS_2ND_BOOT_LATER_ERASE
344         ret = flash_erase(ota_info->partition_start_addr, ota_info->partition_length);
345         if(ret < 0) {
346             printf("erase err.\n");
347             return -1;
348         }
349         #endif
350     }
351     if(flag == 0) {
352         printf("\r\naddr 0x%x is err \n", addr);
353         return -1;
354     }
355     printf("\r\nPlease start ymodem ... (press ctrl+c to cancel)\r\n");
356     ymodem_flash_addr = addr;
357     ret = ymodem_recv_file(addr);
358     while((1) && (ret != YMODEM_OK)) {
359         if(uart_recv_byte(&c)) {
360             break;
361         }
362     }
363     if(ret == YMODEM_OK) {
364         printf("\r\nRecv flash addr: 0x%08x, len:0x%08x OK \n", addr, ymodem_flash_size);
365     } else if(ret == YMODEM_FILE_TOOBIG) {
366         printf("\r\nfile too big len:0x%08x !!!\n", ymodem_flash_size);
367     } else {
368         printf("\r\nYmodem recv file Err:%d !!!\n", ret);
369     }
370     return ret;
371 }
372