tizen 2.4 release
[kernel/u-boot-tm1.git] / nand_fdl / fdl-2 / src / fdl_nand_operate.c
1 #include <asm/arch/packet.h>
2 #include "fdl_conf.h"
3 #include "parsemtdparts.h"
4 #include "asm/arch/nand_controller.h"
5 #include <linux/mtd/mtd.h>
6 #include <linux/mtd/ubi.h>
7 #include <nand.h>
8 #include <linux/mtd/nand.h>
9 #include <malloc.h>
10 #include <ubi_uboot.h>
11 #include "fdl_ubi.h"
12 #include "fdl_common.h"
13 #include "fdl_nand_operate.h"
14 #ifdef CONFIG_SECURE_BOOT
15 #include "secure_verify.h"
16 #endif
17
18 typedef struct {
19         char *vol;
20         char *bakvol;
21 }dl_nv_info_t;
22
23 typedef struct {
24         char *name;  //mtd partition name
25         unsigned long long size;  //mtd part size
26         unsigned long long rw_point;  //nand flash read/write offset point
27 }dl_mtd_info_t;
28
29 typedef struct {
30         struct ubi_device *dev;
31         int dev_num;
32         char *cur_volnm;
33         struct ubi_volume_desc *cur_voldesc;
34 }dl_ubi_info_t;
35
36 typedef enum{
37         PART_TYPE_MIN,
38         PART_TYPE_MTD,
39         PART_TYPE_UBI,
40         PART_TYPE_MAX
41 }dl_part_type;
42
43 typedef struct fdl_download_status
44 {
45         nand_info_t *nand;
46         dl_part_type part_type;
47         dl_mtd_info_t mtd;
48         dl_ubi_info_t ubi;
49         unsigned long total_dl_size;  //size to be recvd
50         unsigned long recv_size;  //recv size from tool
51         unsigned long unsv_size; //data unsaved in buf
52         char *buf;  //buf for data received from tool
53         unsigned int bufsize;  //max buf size
54         unsigned int rp; //read point of buf,no use now
55         unsigned int wp;  //write point of buf
56 }dl_status_t;
57
58 typedef struct{
59         char name[UBI_VOL_NAME_MAX+1];
60         long long size;//size in byte
61         int autoresize;
62 }fdl_ubi_vtbl_t;
63
64 typedef struct {
65         char *name;
66         long long size;
67         int autoresize;
68         struct list_head list;
69 }fdl_ubi_cvol_t;
70
71 #define UBIFS_NODE_MAGIC  0x06101831
72 #define AUTO_RESIZE_FLAG  0xFFFFFFFF
73 #ifdef CONFIG_SECURE_BOOT
74 #define FDL_BUF_LEN  (100*1024*1024)
75 #else
76 #define FDL_BUF_LEN  (1*1024*1024)
77 #endif
78 static dl_status_t dl_stat={0};
79 static char fdl_buf[FDL_BUF_LEN];
80 extern struct ubi_selected_dev cur_ubi;
81 static dl_nv_info_t s_nv_backup_cfg[]={
82         {"fixnv1",                      "fixnv2"},
83         {"runtimenv1",  "runtimenv2"},
84         {"tdfixnv1",            "tdfixnv2"},
85         {"tdruntimenv1",        "tdruntimenv2"},
86         {"wfixnv1",             "wfixnv2"},
87         {"wruntimenv1", "wruntimenv2"},
88         {"wcnfixnv1",           "wcnfixnv2"},
89         {"wcnruntimenv1",       "wcnruntimenv2"},
90         {NULL,NULL}
91 };
92
93 #ifdef CONFIG_SECURE_BOOT
94 static int secure_image_flag = 0;
95 static int check_secure_flag = 0;
96
97 static char* const s_force_secure_check[]={
98         "spl","2ndbl","boot","recovery","tdmodem","tddsp","wmodem","wdsp","wcnmodem",NULL
99 };
100
101 static int  _nand_check_secure_part(wchar_t *partition_name)
102 {
103         int i = 0;
104         do
105         {
106                 if(0 == strcmp(s_force_secure_check[i], partition_name))
107                         return i;
108                 i++;
109         }while(s_force_secure_check[i]!=0);
110
111         return -1;
112 }
113
114 #endif
115
116
117 static __inline void _send_rsp(unsigned long err)
118 {
119     FDL_SendAckPacket(convert_err(err));
120 }
121
122 static struct mtd_info* _get_cur_nand(void)
123 {
124         if ((nand_curr_device < 0) || (nand_curr_device >= CONFIG_SYS_MAX_NAND_DEVICE))
125         {
126                 printf("--->get current nand failed<---\n");
127                 _send_rsp(NAND_UNKNOWN_DEVICE);
128                 return NULL;
129         }
130         return &nand_info[nand_curr_device];
131 }
132
133 /**
134  * check whether is a nv volume.
135  * return backup nv volume in case of true, otherwise null.
136  */
137 static char* _is_nv_volume(char *volume)
138 {
139         int i;
140
141         for(i=0; s_nv_backup_cfg[i].vol !=NULL; i++) {
142                 if(0 == strcmp(volume, s_nv_backup_cfg[i].vol)) {
143                         return s_nv_backup_cfg[i].bakvol;
144                 }
145         }
146         return NULL;
147 }
148
149 /**
150  * parse mtd partitions from a string.
151  */
152 static int _parse_mtd_partitions(void)
153 {
154         struct mtd_info *nand = NULL;
155
156         nand = _get_cur_nand();
157         if(!nand)
158                 return 0;
159         parse_cmdline_partitions(nand->size);
160         return 1;
161 }
162
163 /**
164  * get mtd partition info from partition table parsed.
165  */
166 static int _get_mtd_partition_info(char *name, struct mtd_partition *part)
167 {
168         int ret;
169
170         if(!_parse_mtd_partitions())
171                 return 0;
172
173         ret = parse_mtd_part_info(name, part);
174         if(ret != 1)
175                 return 0;
176
177         return 1;       
178 }
179
180 /**
181  * add volume info to change list.
182  */
183 static int _fdl2_add_to_list(char *name, long long size, int autoresize,
184                                                 struct list_head *list)
185 {
186         fdl_ubi_cvol_t *cvol;
187
188         cvol = malloc(sizeof(fdl_ubi_cvol_t));
189         if(!cvol) {
190                 printf("%s: malloc failed.\n",__func__);
191                 _send_rsp(NAND_SYSTEM_ERROR);
192                 return -ENOMEM;
193         }
194
195         cvol->name = name;
196         cvol->size = size;
197         cvol->autoresize = autoresize;
198         list_add_tail(&cvol->list, list);
199         return 0;
200 }
201
202 /**
203  * parse volume table config, just compatible with dl tool.
204  */
205 static void _fdl2_parse_volume_cfg(unsigned short* vol_cfg, unsigned short total_num, fdl_ubi_vtbl_t *vtbl)
206 {
207         int i, j;
208         long long size;
209
210         /*Decode String: Partition Name(72Byte)+SIZE(4Byte)+...*/
211         for(i=0;i<total_num;i++)
212         {
213                 size = *(unsigned long *)(vol_cfg+38*(i+1)-2);
214                 //the partition size received from tool is MByte.
215                 if(AUTO_RESIZE_FLAG == size){
216                         vtbl[i].size = 1024*1024;//just set size as 1M when autoresize flag enable
217                         vtbl[i].autoresize = 1;
218                 }
219                 else
220                         vtbl[i].size = 1024*1024*size;
221
222                 for(j=0;j<36;j++)
223                 {
224                         //convert name wchar to char with violent
225                         vtbl[i].name[j] = *(vol_cfg+38*i+j) & 0xFF;
226                 }
227
228                 printf("volume name:%s,size:0x%llx,autoresize flag:%d\n",vtbl[i].name,vtbl[i].size,vtbl[i].autoresize);
229         }
230         return;
231 }
232
233 /**
234  * update the nv volume with nv header.
235  */
236 static int _fdl2_update_nv(char *vol, char *bakvol, int size, char *data)
237 {
238         int ret,time=1;
239         char *buf;
240         char *nvbuf=NULL;
241         char *curvol;
242         char tmp[NV_HEAD_LEN];
243         nv_header_t *header;
244
245         if(size>dl_stat.bufsize){
246                 nvbuf = malloc(size+NV_HEAD_LEN);
247                 if(!nvbuf){
248                         printf("%s buf malloc failed.\n",__func__);
249                         return -1;
250                 }
251                 buf = nvbuf;
252                 fdl_ubi_volume_read(dl_stat.ubi.dev, dl_stat.ubi.cur_volnm, buf, size, 0);
253                 if(size != ret) {
254                         printf("%s read volume %s failed.\n",__func__,dl_stat.ubi.cur_volnm);
255                         goto err;
256                 }
257         }else {
258                 buf = data;
259         }
260
261         memset(tmp,0x0,NV_HEAD_LEN);
262         header = (nv_header_t *)tmp;
263         header->magic = NV_HEAD_MAGIC;
264         header->version = NV_VERSION;
265         header->len = size;
266         header->checksum = fdl_calc_checksum(buf,size);
267         curvol = vol;
268         do{
269                 ret = fdl_ubi_volume_start_update(dl_stat.ubi.dev, curvol, size+NV_HEAD_LEN);
270                 if(ret) {
271                         printf("%s: vol %s start update failed!\n",__func__,curvol);
272                         goto err;
273                 }
274                 ret = fdl_ubi_volume_write(dl_stat.ubi.dev, curvol, tmp, NV_HEAD_LEN);
275                 if(ret) {
276                         printf("%s volume write error %d!\n",curvol,ret);
277                         goto err;
278                 }
279                 ret = fdl_ubi_volume_write(dl_stat.ubi.dev, curvol, buf, size);
280                 if(ret) {
281                         printf("%s volume write error %d!\n",curvol,ret);
282                         goto err;
283                 }
284                 curvol = bakvol;
285         }while(time--);
286
287         printf("update nv success!\n");
288         return 0;
289 err:
290         if(nvbuf)
291                 free(nvbuf);
292         return -1;
293 }
294 static int _fdl2_check_nv(char *vol)
295 {
296         char *buf = 0,*bakbuf = 0,*pbakvol = 0;
297         nv_header_t *header;
298         int ret = NAND_SYSTEM_ERROR;
299         int size = FIXNV_SIZE+NV_HEAD_LEN;
300         uint8  status_nand =0;
301         int chkRet = -1;
302 /*read org*/
303         buf = malloc(size);
304         if(!buf){
305                 printf("%s buf malloc failed.\n",__func__);
306                 goto out;
307         }
308         ret = fdl_ubi_volume_read(dl_stat.ubi.dev,vol,buf,size,0);
309         if(size != ret){
310                 printf("%s can read 0x%x data from vol %s ret %d!!\n",__func__,size,vol,ret);
311         }
312         else{
313                 header = (nv_header_t *)buf;
314                 ret = fdl_check_crc(buf+NV_HEAD_LEN, header->len, header->checksum);
315                 if(ret){
316                         status_nand |=1;
317                         printf("%s org nv is ok.\n",__func__);
318                 }
319                 else{
320                         printf("%s org nv is damaged.\n",__func__);
321                 }
322         }
323
324 /*read backup*/
325         bakbuf = malloc(size);
326         if(!bakbuf){
327                 printf("%s bakbuf malloc failed.\n",__func__);
328                 goto out;
329         }
330         printf("%s bakbuf malloc succees.\n",__func__);
331         pbakvol=_is_nv_volume(vol);
332         if(!pbakvol){
333                 goto out;
334         }
335         ret = fdl_ubi_volume_read(dl_stat.ubi.dev, pbakvol,bakbuf,size,0);
336         if(size != ret){
337                 printf("%s can read 0x%x data from bakup %s ret %d!!!\n",__func__,size,pbakvol,ret);
338         }
339         else{
340                 header = (nv_header_t *)bakbuf;
341                 ret = fdl_check_crc(bakbuf+NV_HEAD_LEN, header->len, header->checksum);
342                 if(ret){
343                         status_nand |=2;
344                         printf("%s bak nv is ok.\n",__func__);
345                 }
346                 else{
347                         printf("%s bak nv is damaged.\n",__func__);
348                 }
349         }
350         switch(status_nand){
351                 case 0:
352                         printf("%s both org and bak nv are damaged.\n",__func__);
353                          goto out;
354                 break;
355                 case 1:
356                         printf("%s  bak nv is damaged.\n",__func__);
357                         fdl_ubi_volume_start_update(dl_stat.ubi.dev, pbakvol, size);
358                         ret = fdl_ubi_volume_write(dl_stat.ubi.dev,pbakvol, buf, size);
359                         if(ret){
360                                 printf("%s bak ubi volume write error %d!\n",__func__,ret);
361                                 goto out;
362                         }
363                         chkRet = 0;
364                 break;
365                 case 2:
366                         printf("%s  org nv is damaged.\n",__func__);
367                         fdl_ubi_volume_start_update(dl_stat.ubi.dev, vol, size);
368                         ret = fdl_ubi_volume_write(dl_stat.ubi.dev, vol, bakbuf, size);
369                         if(ret){
370                                 printf("%s org ubi volume write error %d!\n",__func__,ret);
371                                 goto out;
372                         }
373                         chkRet = 0;
374                 break;
375                 case 3:
376                         printf("%s both org and bak nv are ok.\n",__func__);
377                         chkRet = 0;
378                 break;
379                 default:
380                         printf("%s: status_nand error!\n",__func__);
381                         goto out;
382                 break;
383         }
384 out:
385         if(bakbuf){
386                 free(bakbuf);
387         }
388         if(buf){
389                 free(buf);
390         }
391         return chkRet;
392 }
393
394 /**
395  * check whether the new volumes table same with original.
396  * return 0 in case of diff and 1 in case of same.
397  */
398 static int _fdl2_vtbl_check(fdl_ubi_vtbl_t *vtbl, int total_vols, struct list_head *rm, struct list_head *mk)
399 {
400         int i,j;
401         int arid=-1;
402         int same=0,fulleq=1;
403         struct ubi_volume *vol;
404         struct ubi_device *ubi = cur_ubi.dev;
405
406         if(!cur_ubi.ubi_initialized){
407                 printf("%s:ubi init failed.\n",__FUNCTION__);
408                 return -1;
409         }
410
411         if(!(ubi->vol_count-UBI_INT_VOL_COUNT)){
412                 printf("%s:empty ubi device.\n",__FUNCTION__);
413                 return -1;
414         }
415
416         if(total_vols != (ubi->vol_count-UBI_INT_VOL_COUNT)){
417                 printf("%s:new vol count is %d,old vol count is %d.\n",
418                         __FUNCTION__,total_vols,ubi->vol_count-UBI_INT_VOL_COUNT);
419                 fulleq = 0;
420         }
421
422         for(i=0;i<total_vols;i++){
423                 same = 0;
424                 for (j = 0; j < ubi->vtbl_slots; j++) {
425                         vol = ubi->volumes[j];
426                         if (vol && !strcmp(vol->name, vtbl[i].name)) {
427                                 printf("Volume \"%s\" found at volume id %d.\n", vtbl[i].name, j);
428                                 if(vtbl[i].autoresize){
429                                         //autoresize_vol_id flag will set -1 after ubi attach, so we can't get it.
430                                         same = 1;
431                                         arid = i;
432                                 }else{
433                                         int new_rsvd_pebs=0;
434                                         uint64_t bytes = vtbl[i].size;
435                                         if (do_div(bytes, vol->usable_leb_size))
436                                                 new_rsvd_pebs = 1;
437                                         new_rsvd_pebs += bytes;
438                                         if(new_rsvd_pebs == vol->reserved_pebs)
439                                                 same = 1;
440                                         else
441                                                 printf("reserved pebs not same,new %d,old %d.\n",new_rsvd_pebs,vol->reserved_pebs);
442                                         if(!same){
443                                                 printf("add volume \"%s\" to remove list.\n", vtbl[i].name);
444                                                 _fdl2_add_to_list(vtbl[i].name,0,0,rm);
445                                         }
446                                 }
447                                 break;
448                         }
449                 }
450                 if (!same) {
451                         fulleq = 0;
452                         printf("add volume \"%s\" to create list.\n", vtbl[i].name);
453                         _fdl2_add_to_list(vtbl[i].name,vtbl[i].size,vtbl[i].autoresize,mk);
454                 }
455         }
456
457         for(i = 0; i < ubi->vtbl_slots; i++) {
458                 same = 0;
459                 vol = ubi->volumes[i];
460                 if(!vol)
461                         continue;
462                 printf("old volume slot: %d, name \"%s\"\n",i,vol->name);
463                 for(j = 0; j < total_vols; j++) {
464                         if(!strcmp(vol->name, vtbl[j].name)) {
465                                 same = 1;
466                                 break;
467                         }
468                 }
469                 if(!same) {
470                         fulleq = 0;
471                         printf("add volume \"%s\" to remove list.\n", vol->name);
472                         _fdl2_add_to_list(vol->name,0,0,rm);
473                 }
474         }
475
476         if(fulleq) {
477                 return 1;
478         }else {
479                 if(arid >= 0) {
480                         printf("add autoresize volume \"%s\" to rm/mk list.\n", vtbl[arid].name);
481                         _fdl2_add_to_list(vtbl[arid].name,0,0,rm);
482                         _fdl2_add_to_list(vtbl[arid].name,vtbl[arid].size,vtbl[arid].autoresize,mk);
483                 }
484                 return 0;
485         }
486 }
487 /**
488  * nand write and dl_stat update.
489  */
490 static void _fdl2_nand_write(nand_info_t *nand, unsigned long long offset, unsigned long length,
491                         char *buffer)
492 {
493         int ret;
494
495         //printf("fdl_nand_write:offset:0x%llx,len:0x%x\n",offset,length);
496
497         //TODO:temp here for step 1 debug
498         if(strcmp(dl_stat.mtd.name, "spl")==0){
499                 sprd_nand_write_spl(buffer, dl_stat.nand);
500                 printf("write spl\n");
501                 dl_stat.wp =0;
502                 dl_stat.unsv_size =0;
503                 return;
504         }
505
506         switch(dl_stat.part_type){
507                 case PART_TYPE_MTD:
508                         ret = nand_write_skip_bad(nand, offset, &length, buffer);
509                         dl_stat.unsv_size -= length;
510                         memmove(dl_stat.buf, dl_stat.buf+length, dl_stat.unsv_size);
511                         dl_stat.wp -= length;
512                         dl_stat.mtd.rw_point += length;
513                         if(ret){
514                                 //mark a block as badblock
515                                 printf("nand write error %d, mark bad block 0x%llx\n",ret,dl_stat.mtd.rw_point&~(nand->erasesize-1));
516                                 nand->block_markbad(nand,dl_stat.mtd.rw_point&~(nand->erasesize-1));
517                         }
518                         break;
519                 case PART_TYPE_UBI:
520                         ret = fdl_ubi_volume_write(dl_stat.ubi.dev, dl_stat.ubi.cur_volnm, buffer, length);
521                         if(ret){
522                                 printf("ubi volume write error %d!\n",ret);
523                                 _send_rsp(NAND_SYSTEM_ERROR);
524                         }
525                         dl_stat.unsv_size -= length;
526                         memmove(dl_stat.buf, dl_stat.buf+length, dl_stat.unsv_size);
527                         dl_stat.wp -= length;
528                         break;
529                 default:
530                         printf("%s: part type error!\n",__FUNCTION__);
531                         return;
532         }
533
534         return;
535 }
536
537 /**
538  * erase the given mtd part.
539  * return 0 in case of success.
540  */
541 static int _fdl2_mtd_part_erase(char *name)
542 {
543         int ret;
544         struct mtd_partition mtd_part;
545         nand_erase_options_t opts;
546
547         ret = _get_mtd_partition_info(name, &mtd_part);
548         if(ret){
549                 memset(&opts, 0, sizeof(opts));
550                 opts.offset = mtd_part.offset;
551                 opts.length = mtd_part.size;
552                 opts.quiet  = 1;
553                 ret = nand_erase_opts(_get_cur_nand(), &opts);
554                 if(!ret)
555                         return 0;
556                 printf("%s:nand erase %s failure %d\n",__FUNCTION__, name, ret);
557         }else
558                 printf("%s:Can't find part %s",__FUNCTION__,name);
559         return 1;
560 }
561
562 /**
563  * parse the given part is mtd partition or ubi volume.
564  */
565 static void _fdl2_part_info_parse(char *part)
566 {
567         int ret;
568         struct mtd_partition mtd_part;
569         struct ubi_volume_desc *vol;
570
571         ret = _get_mtd_partition_info(part, &mtd_part);
572         if(ret){
573                 dl_stat.mtd.name = part;
574                 dl_stat.mtd.size = mtd_part.size;
575                 dl_stat.mtd.rw_point = mtd_part.offset;
576                 dl_stat.part_type = PART_TYPE_MTD;
577                 return;
578         }
579
580         vol = ubi_open_volume_nm(cur_ubi.dev_num, part, UBI_READWRITE);
581         if (IS_ERR(vol)){
582                 printf("cannot open volume \"%s\", error %d\n",part, (int)PTR_ERR(vol));
583         }else{
584                 dl_stat.ubi.dev = cur_ubi.dev;
585                 dl_stat.ubi.dev_num = cur_ubi.dev_num;
586                 dl_stat.ubi.cur_volnm = part;
587                 dl_stat.ubi.cur_voldesc = vol;
588                 dl_stat.part_type = PART_TYPE_UBI;
589                 return;
590         }
591         dl_stat.part_type = PART_TYPE_MAX;
592         printf("Can't find part %s.\n",part);
593         return;
594 }
595
596 /**
597  * fdl2_download_start
598  *
599  * Get download info from download start command which  
600  * will used in next step
601  *
602  * @param part partition/volume name
603  * @param size total download size
604  * @param nv_checksum NA
605  * @return 0 failed
606  *             1 success
607  */
608 int fdl2_download_start(char* name, unsigned long size, unsigned long nv_checksum)
609 {
610         int ret;
611         int index;
612
613 #ifdef CONFIG_SECURE_BOOT
614         printf("fdl2_download_start(): check secure part. name:%s, size:%d.\n", name, size);
615         index = _nand_check_secure_part(name);
616         if(index != -1)
617         {
618                 printf("fdl2_download_start(): the part should be checked. %s\n", name);
619                 /*because there is no secure header flag in the spl image.*/
620                 if (strcmp(name, "spl") == 0){
621                         secure_image_flag = 1;
622                         check_secure_flag = 0;
623                 }
624                 else{
625                         secure_image_flag = 0;
626                         check_secure_flag = 1;
627                 }
628         }else
629         {
630                 secure_image_flag = 0;
631                 check_secure_flag = 0;
632         }
633 #endif
634
635         memset(&dl_stat, 0x0, sizeof(dl_status_t));
636
637         _fdl2_part_info_parse(name);
638
639         switch(dl_stat.part_type){
640                 case PART_TYPE_MTD:
641                         if(size > dl_stat.mtd.size){
642                                 printf("%s:dl size 0x%x > partition size 0x%llx\n",__FUNCTION__,size,dl_stat.mtd.size);
643                                 ret = NAND_INVALID_SIZE;
644                                 goto err;
645                         }
646 #ifdef CONFIG_SECURE_BOOT
647                         if (!secure_image_flag && !check_secure_flag){
648 #endif
649                         ret = _fdl2_mtd_part_erase(name);
650                         if(ret){
651                                 printf("%s:mtd %d erase failed!\n",__FUNCTION__,name);
652                                 ret = NAND_SYSTEM_ERROR;
653                                 goto err;
654                         }
655 #ifdef CONFIG_SECURE_BOOT
656                         }
657 #endif
658
659                         break;
660                 case PART_TYPE_UBI:
661                         if(size > dl_stat.ubi.cur_voldesc->vol->used_bytes){
662                                 printf("dl size > partition size!\n");
663                                 ret = NAND_INVALID_SIZE;
664                                 goto err;
665                         }
666 #ifdef CONFIG_SECURE_BOOT
667                         if (!secure_image_flag && !check_secure_flag){
668 #endif
669                         ret = fdl_ubi_volume_start_update(dl_stat.ubi.dev, name, size);
670                         if(ret){
671                                 printf("%s: vol %s start update failed!\n",__FUNCTION__,name);
672                                 ret = NAND_SYSTEM_ERROR;
673                                 goto err;
674                         }
675 #ifdef CONFIG_SECURE_BOOT
676                         }
677 #endif
678
679                         break;
680                 default:
681                         ret = NAND_INCOMPATIBLE_PART;
682                         goto err;
683         }
684
685         dl_stat.nand = _get_cur_nand();
686         dl_stat.total_dl_size = size;
687         dl_stat.recv_size = 0;
688         dl_stat.unsv_size = 0;
689         dl_stat.buf = fdl_buf;
690         dl_stat.bufsize = FDL_BUF_LEN;
691         dl_stat.rp = 0;
692         dl_stat.wp = 0;
693
694         printf("fdl2_download_start:part:%s,size:0x%x\n",name,size);
695
696         _send_rsp(NAND_SUCCESS);
697         return 1;
698 err:
699         _send_rsp(ret);
700         return 0;
701 }
702
703 /**
704  * fdl2_download_midst
705  *
706  * Save data to fdl buf and finally write it to nand flash
707  *
708  * @param size total download size
709  * @param buf data recvd
710  * @return 0 failed
711  *             1 success
712  */
713 int fdl2_download_midst(unsigned short size, char *buf)
714 {
715         int ret =0;
716         unsigned int cpy_len=0,unsv_len=0;
717         unsigned long len;
718         nand_info_t *nand;
719
720 #ifdef CONFIG_SECURE_BOOT
721         if(check_secure_flag == 1)
722         {
723                 check_secure_flag = 0;
724                 if (secure_header_parser(buf) != 1)
725                 {
726                         secure_image_flag = 0;
727                         _send_rsp(NAND_SYSTEM_ERROR);
728                         return 0;
729                 }
730                 else {
731                         secure_image_flag = 1;
732                 }
733         }
734
735         if (secure_image_flag == 1){
736                 dl_stat.recv_size += size;
737                 unsv_len = size;
738                 memcpy(dl_stat.buf+dl_stat.wp, &buf[size-unsv_len], unsv_len);
739                 dl_stat.wp += unsv_len;
740                 dl_stat.unsv_size += unsv_len;
741
742                 _send_rsp(NAND_SUCCESS);
743                 return 1;
744         }
745 #endif
746
747         nand = dl_stat.nand;
748         dl_stat.recv_size += size;
749         unsv_len = size;
750         while((dl_stat.unsv_size+unsv_len)> dl_stat.bufsize)
751         {
752                 len = dl_stat.unsv_size;
753                 len = len & ~(nand->erasesize - 1);
754
755                 _fdl2_nand_write(nand, dl_stat.mtd.rw_point, len, dl_stat.buf);
756
757                 cpy_len = dl_stat.bufsize - dl_stat.unsv_size;
758                 cpy_len = (unsv_len>cpy_len)?cpy_len:unsv_len;
759                 memcpy(dl_stat.buf+dl_stat.wp, &buf[size-unsv_len], cpy_len);
760                 unsv_len -= cpy_len;
761                 dl_stat.wp += cpy_len;
762                 dl_stat.unsv_size += cpy_len;
763         }
764
765         //copy data to dl buf
766         memcpy(dl_stat.buf+dl_stat.wp, &buf[size-unsv_len], unsv_len);
767         dl_stat.wp += unsv_len;
768         dl_stat.unsv_size += unsv_len;
769
770         if(dl_stat.recv_size == dl_stat.total_dl_size){
771                 len = dl_stat.unsv_size;
772                 _fdl2_nand_write(nand, dl_stat.mtd.rw_point, len, dl_stat.buf);
773         }
774
775         _send_rsp(NAND_SUCCESS);
776         return 1;
777 }
778
779 /**
780  * fdl2_download_end
781  *
782  * Set download end
783  *
784  * @param void
785  * @return 0 failed
786  *             1 success
787  */
788 int fdl2_download_end(void)
789 {
790         int i=0;
791         char* name;
792         int index;
793         int ret = NAND_SUCCESS;
794
795 #ifdef CONFIG_SECURE_BOOT
796         if (secure_image_flag){
797                 if (dl_stat.part_type == PART_TYPE_MTD){
798                         name = dl_stat.mtd.name;
799                 }
800                 else if (dl_stat.part_type == PART_TYPE_UBI){
801                         name = dl_stat.ubi.cur_volnm;
802                 }
803                 else{
804                         _send_rsp(NAND_SYSTEM_ERROR);
805                         return 0;
806                 }
807
808                 if (strcmp(name, "spl") == 0){
809                         secure_verify(L"splloader0", dl_stat.buf, 0);
810                 }
811                 else if (strcmp(name, "2ndbl") == 0){
812                         secure_verify(L"splloader", dl_stat.buf, 0);
813                 }
814                 else{
815                         secure_verify(L"fdl2", dl_stat.buf, 0);
816                 }
817
818                 switch(dl_stat.part_type){
819                         case PART_TYPE_MTD:
820                                 ret = _fdl2_mtd_part_erase(name);
821                                 if(ret){
822                                         printf("%s:mtd %d erase failed!\n",__FUNCTION__, name);
823                                         ret = NAND_SYSTEM_ERROR;
824                                 }
825                                 break;
826                         case PART_TYPE_UBI:
827                                 ret = fdl_ubi_volume_start_update(dl_stat.ubi.dev, name, dl_stat.total_dl_size);
828                                 if(ret){
829                                         printf("%s: vol %s start update failed!\n",__FUNCTION__, name);
830                                         ret = NAND_SYSTEM_ERROR;
831                                 }
832                                 break;
833                         default:
834                                 break;
835                 }
836                 if (ret != NAND_SUCCESS){
837                         _send_rsp(ret);
838                         return 0;
839                 }
840         }
841 #endif
842
843         while(0 != dl_stat.unsv_size){
844                 _fdl2_nand_write(dl_stat.nand, dl_stat.mtd.rw_point, dl_stat.unsv_size, dl_stat.buf);
845                 if(i++>1){
846                         printf("download end write error, try 2 times.\n");
847                         _send_rsp(NAND_SYSTEM_ERROR);
848                         return 0;
849                 }
850         }
851         //close opened ubi volume
852         if(PART_TYPE_UBI == dl_stat.part_type){
853                 int err;
854                 char *bakvol;
855                 bakvol = _is_nv_volume(dl_stat.ubi.cur_volnm);
856                 if(bakvol) {
857                         err = _fdl2_update_nv(dl_stat.ubi.cur_volnm, 
858                                                         bakvol,
859                                                         dl_stat.total_dl_size,
860                                                         dl_stat.buf);
861                         if(err)
862                                 ret = NAND_SYSTEM_ERROR;
863                 }
864                 ubi_close_volume(dl_stat.ubi.cur_voldesc);
865         }
866
867 #ifdef CONFIG_SECURE_BOOT
868         secure_image_flag = 0;
869         check_secure_flag = 0;
870 #endif
871         _send_rsp(ret);
872         return 1;
873 }
874
875 /**
876  * fdl2_read_start
877  *
878  * Get partition/volume info from read start command which  
879  * will used in next step
880  *
881  * @param part partition/volume name
882  * @param size total size
883  * @return 0 failed
884  *             1 success
885  */
886 int fdl2_read_start(char* part, unsigned long size)
887 {
888         int ret;
889
890         memset(&dl_stat, 0x0, sizeof(dl_status_t));
891
892         _fdl2_part_info_parse(part);
893
894         switch(dl_stat.part_type){
895                 case PART_TYPE_MTD:
896                         if(size > dl_stat.mtd.size){
897                                 printf("%s:read size 0x%x > partition size 0x%llx\n",__FUNCTION__,size,dl_stat.mtd.size);
898                                 ret = NAND_INVALID_SIZE;
899                                 goto err;
900                         }
901                         break;
902                 case PART_TYPE_UBI:
903                         if(size > dl_stat.ubi.cur_voldesc->vol->used_bytes){
904                                 printf("%s:read size 0x%x > partition size 0x%llx\n",__FUNCTION__,size,dl_stat.ubi.cur_voldesc->vol->used_bytes);
905                                 ret = NAND_INVALID_SIZE;
906                                 goto err;
907                         }
908                         if(_is_nv_volume(dl_stat.ubi.cur_volnm)) {
909                                 _fdl2_check_nv(dl_stat.ubi.cur_volnm);
910                         }
911                         if(!strcmp(dl_stat.ubi.cur_volnm, "prodnv")) {
912                                 u32 magic;
913                                 fdl_ubi_volume_read(dl_stat.ubi.dev,
914                                                                 dl_stat.ubi.cur_volnm,
915                                                                 &magic,
916                                                                 sizeof(u32),
917                                                                 0);
918                                 if(magic != UBIFS_NODE_MAGIC) {
919                                         printf("bad ubifs node magic %#08x, expected %#08x\n",
920                                                 magic, UBIFS_NODE_MAGIC);
921                                         ret = NAND_SYSTEM_ERROR;
922                                         goto err;
923                                 }
924                         }
925                         break;
926                 default:
927                         printf("%s:Incompatible part %s!\n",__FUNCTION__,part);
928                         ret = NAND_INCOMPATIBLE_PART;
929                         goto err;
930         }
931
932         dl_stat.nand = _get_cur_nand();
933         printf("fdl2_read_start:%s,size:0x%x\n",part,size);
934
935         _send_rsp(NAND_SUCCESS);
936         return 1;
937 err:
938         _send_rsp(ret);
939         return 0;
940 }
941
942 /**
943  * fdl2_read_midst
944  *
945  * Read partition/volume data
946  *
947  * @param size size to be read
948  * @param off offset of begin of part/vol
949  * @param buf data saved
950  * @return 0 failed
951  *             1 success
952  */
953 int fdl2_read_midst(unsigned long size, unsigned long off, unsigned char *buf)
954 {
955         int ret;
956
957         switch(dl_stat.part_type){
958                 case PART_TYPE_MTD:
959                         ret = nand_read_skip_bad(dl_stat.nand, dl_stat.mtd.rw_point+off, &size, buf);
960                         if(ret)
961                                 goto err;
962                         break;
963                 case PART_TYPE_UBI:
964                         if(_is_nv_volume(dl_stat.ubi.cur_volnm)) {
965                                 off += NV_HEAD_LEN;
966                         }
967                         ret = fdl_ubi_volume_read(dl_stat.ubi.dev, 
968                                                                 dl_stat.ubi.cur_volnm,
969                                                                 buf,
970                                                                 size,
971                                                                 off);
972                         if(size != ret)
973                                 goto err;
974                         break;
975                 default:
976                         printf("%s:part type err!\n",__FUNCTION__);
977                         goto err;
978         }
979
980         return 1;
981 err:
982         printf("%s:read error %d!\n",__FUNCTION__, ret);
983         _send_rsp(NAND_SYSTEM_ERROR);
984         return 0;
985 }
986
987 /**
988  * fdl2_read_end
989  *
990  * Set read flash end
991  *
992  * @param void
993  * @return 0 failed
994  *             1 success
995  */
996 int fdl2_read_end(void)
997 {
998         //close opened ubi volume
999         if(PART_TYPE_UBI == dl_stat.part_type){
1000                 ubi_close_volume(dl_stat.ubi.cur_voldesc);
1001         }
1002
1003         _send_rsp(NAND_SUCCESS);
1004         return 1;
1005 }
1006
1007 /**
1008  * fdl2_erase
1009  *
1010  * Erase partition/volume
1011  *
1012  * @param part partition/volume name
1013  * @param size size to be erased(no use now)
1014  * @return 0 failed
1015  *             1 success
1016  */
1017 int fdl2_erase(char* part, unsigned long size)
1018 {
1019         int ret;
1020         char * bak_vol;
1021
1022         if(!strcmp(part, "erase_all")){
1023                 struct mtd_info *nand = NULL;
1024                 nand_erase_options_t opts;
1025
1026                 memset(&opts, 0, sizeof(opts));
1027                 nand = _get_cur_nand();
1028                 opts.offset = 0;
1029                 opts.length = nand->size;
1030                 opts.quiet  = 1;
1031                 ret = nand_erase_opts(nand, &opts);
1032                 if(ret){
1033                         ret =NAND_SYSTEM_ERROR;
1034                         goto err;
1035                 }
1036                 //reinit after erase all
1037                 fdl_ubi_dev_init();
1038                 goto end;
1039         }
1040
1041         _fdl2_part_info_parse(part);
1042
1043         switch(dl_stat.part_type){
1044                 case PART_TYPE_MTD:
1045                         ret = _fdl2_mtd_part_erase(part);
1046                         if(ret){
1047                                 printf("%s:mtd %d erase failed!\n",__FUNCTION__,part);
1048                                 ret = NAND_SYSTEM_ERROR;
1049                                 goto err;
1050                         }
1051                         break;
1052                 case PART_TYPE_UBI:
1053                         bak_vol = _is_nv_volume(dl_stat.ubi.cur_volnm);
1054                         if(bak_vol){
1055                                 ret = fdl_ubi_volume_start_update(dl_stat.ubi.dev, bak_vol, 0);
1056                                 if(ret){
1057                                         printf("backup %s: vol %s erase failed!\n",__FUNCTION__,part);
1058                                         ret = NAND_SYSTEM_ERROR;
1059                                         goto err;
1060                                 }
1061                         }
1062                         ret = fdl_ubi_volume_start_update(dl_stat.ubi.dev, part, 0);
1063                         if(ret){
1064                                 printf("%s: vol %s erase failed!\n",__FUNCTION__,part);
1065                                 ret = NAND_SYSTEM_ERROR;
1066                                 goto err;
1067                         }
1068                         ubi_close_volume(dl_stat.ubi.cur_voldesc);
1069                         break;
1070                 default:
1071                         printf("%s:Incompatible part %s!\n",__FUNCTION__,part);
1072                         ret = NAND_INCOMPATIBLE_PART;
1073                         goto err;
1074         }
1075 end:
1076         _send_rsp(NAND_SUCCESS);
1077         return 1;
1078 err:
1079         _send_rsp(ret);
1080         return 0;
1081 }
1082
1083 /**
1084  * fdl2_repartition
1085  *
1086  * Resize/Add/Delete volumes
1087  *
1088  * @param vol_cfg volume cfg
1089  * @param total_vol_num
1090  * @return 0 failed
1091  *             1 success
1092  */
1093 int fdl2_repartition(void* vol_cfg, unsigned short total_vol_num)
1094 {
1095         int ret,i,vol_id,auto_resize_id=-1;
1096         fdl_ubi_vtbl_t *vtbl=NULL;
1097         fdl_ubi_cvol_t *cvol,*cvol_tmp;
1098         struct list_head remove;
1099         struct list_head create;
1100
1101         INIT_LIST_HEAD(&remove);
1102         INIT_LIST_HEAD(&create);
1103
1104         vtbl = malloc(total_vol_num * sizeof(fdl_ubi_vtbl_t));
1105         if(!vtbl){
1106                 printf("%s:malloc vtbl failed!\n",__FUNCTION__);
1107                 goto err;
1108         }
1109         memset(vtbl,0x0,total_vol_num*sizeof(fdl_ubi_vtbl_t));
1110         _fdl2_parse_volume_cfg(vol_cfg, total_vol_num, vtbl);
1111
1112         ret = _fdl2_vtbl_check(vtbl, total_vol_num, &remove, &create);
1113         if(ret < 0){
1114                 printf("full repartition.\n");
1115                 goto full_repartition;
1116         } else if (!ret){
1117                 printf("partial repartition.\n");
1118                 goto partial_repartition;
1119         } else{
1120                 printf("ubi volumes are same.\n");
1121                 ret = NAND_SUCCESS;
1122                 goto end;
1123         }
1124
1125 full_repartition:
1126         ret = _fdl2_mtd_part_erase(UBIPAC_PART);
1127         if(ret)
1128                 goto err;
1129         ret = fdl_ubi_dev_init();
1130         if(!ret){
1131                 printf("attach ubi failed after erase!\n");
1132                 goto err;
1133         }
1134         //create volumes
1135         for(i=0;i<total_vol_num;i++){
1136                 ret = fdl_ubi_create_vol(cur_ubi.dev, vtbl[i].name, &vol_id, vtbl[i].size, 1);
1137                 if(ret){
1138                         printf("ubi vol \"%s\" create err %d.\n",vtbl[i].name,ret);
1139                         goto err;
1140                 }
1141                 if(vtbl[i].autoresize){
1142                         auto_resize_id = vol_id;
1143                 }
1144         }
1145         goto autoresize;
1146
1147 partial_repartition:
1148         list_for_each_entry(cvol, &remove, list) {
1149                 printf("partial_repartition remove vol \"%s\" \n",cvol->name);
1150                 ret = fdl_ubi_remove_vol(cur_ubi.dev, cvol->name);
1151                 if(ret){
1152                         printf("ubi vol \"%s\" remove err %d.\n",cvol->name,ret);
1153                         goto err;
1154                 }
1155         }
1156         list_for_each_entry(cvol, &create, list) {
1157                 printf("partial_repartition create vol \"%s\" size:0x%llx atr-flag:%d\n",
1158                         cvol->name,cvol->size,cvol->autoresize);
1159                 ret = fdl_ubi_create_vol(cur_ubi.dev, cvol->name, &vol_id, cvol->size, 1);
1160                 if(ret){
1161                         printf("ubi vol \"%s\" create err %d.\n",cvol->name,ret);
1162                         goto err;
1163                 }
1164                 if(cvol->autoresize){
1165                         auto_resize_id = vol_id;
1166                 }
1167         }
1168
1169 autoresize:
1170         //resize the autoresize volume
1171         if(-1 != auto_resize_id){
1172                 ret = fdl_ubi_volume_autoresize(cur_ubi.dev, auto_resize_id);
1173                 if(ret){
1174                         printf("volume auto resize failed %d.\n",ret);
1175                         goto err;
1176                 }
1177         }
1178
1179         ret = NAND_SUCCESS;
1180 end:
1181         list_for_each_entry_safe(cvol, cvol_tmp, &remove, list) {
1182                 list_del(&cvol->list);
1183                 free(cvol);
1184         }
1185         list_for_each_entry_safe(cvol, cvol_tmp, &create, list) {
1186                 list_del(&cvol->list);
1187                 free(cvol);
1188         }
1189         free(vtbl);
1190         _send_rsp(ret);
1191         return 1;
1192 err:
1193         ret = NAND_SYSTEM_ERROR;
1194         goto end;
1195 }
1196