tizen 2.4 release
[kernel/u-boot-tm1.git] / property / sysdump.c
1 /*
2  * Copyright (C) 2013 Spreadtrum Communications Inc.
3  *
4  * This software is licensed under the terms of the GNU General Public
5  * License version 2, as published by the Free Software Foundation, and
6  * may be copied, distributed, and modified under those terms.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  */
13
14 #include "normal_mode.h"
15 #include <mmc.h>
16 #include <fat.h>
17 #include <rtc.h>
18 #include <asm/sizes.h>
19 #include <boot_mode.h>
20 #include <common.h>
21
22 #include <linux/keypad.h>
23 #include <linux/key_code.h>
24 #include "sysdump.h"
25 #include <linux/mtd/mtd.h>
26 #include <asm/global_data.h>
27
28 extern PUBLIC phys_size_t get_dram_size_from_gd(void);
29
30 extern void MMU_DisableIDCM(void);
31 extern int lcd_display_bitmap(ulong bmp_image, int x, int y);
32 extern lcd_display(void);
33 extern void set_backlight(uint32_t value);
34 extern void lcd_setfgcolor(int color);
35
36 void display_writing_sysdump(void)
37 {
38         debugf("%s\n", __FUNCTION__);
39 #ifdef CONFIG_SPLASH_SCREEN
40
41         vibrator_hw_init();
42         set_vibrator(1);
43         //read boot image header
44         size_t size = 1<<19;
45         char * bmp_img = malloc(size);
46         if(!bmp_img){
47                 debugf("not enough memory for splash image\n");
48                 return;
49         }
50         int ret = read_logoimg(bmp_img,size);
51         if(ret == -1) {
52                 free(bmp_img);
53                 return;
54         }
55         lcd_display_bitmap((ulong)bmp_img, 0, 0);
56         lcd_printf("   -------------------------------  \n"
57                    "   Sysdumpping now, keep power on.  \n"
58                    "   -------------------------------  \n");
59         lcd_display();
60         set_backlight(255);
61         set_vibrator(0);
62
63         free(bmp_img);
64 #endif
65 }
66 void display_special_mode(void)
67 {
68         debugf("%s\n", __FUNCTION__);
69 #ifdef CONFIG_SPLASH_SCREEN
70
71         vibrator_hw_init();
72         set_vibrator(1);
73         //read boot image header
74         size_t size = 1<<19;
75         char * bmp_img = malloc(size);
76         if(!bmp_img){
77                 debugf("not enough memory for splash image\n");
78                 return;
79         }
80         int ret = read_logoimg(bmp_img,size);
81         if(ret == -1) {
82                 free(bmp_img);
83                 return;
84         }
85         lcd_display_bitmap((ulong)bmp_img, 0, 0);
86         lcd_printf("   -------------------------------  \n"
87                    "   Restart now, keep power on.  \n"
88                    "   -------------------------------  \n");
89         lcd_display();
90         set_backlight(255);
91         set_vibrator(0);
92
93         free(bmp_img);
94 #endif
95 }
96 static void wait_for_keypress()
97 {
98         int key_code;
99
100         do {
101                 udelay(50 * 1000);
102                 key_code = board_key_scan();
103                 //printf("key_code: %d, (vd:%d,vu:%d,p:%d)\n", key_code, KEY_VOLUMEDOWN, KEY_VOLUMEUP, KEY_POWER);
104                 if (key_code == KEY_VOLUMEDOWN || key_code == KEY_VOLUMEUP || key_code == KEY_HOME)
105                         break;
106         } while (1);
107         debugf("Pressed key: %d\n", key_code);
108         lcd_printf("Pressed key: %d\n", key_code);
109         lcd_display();
110 }
111
112 int init_mmc_fat(void)
113 {
114         struct mmc *mmc;
115         block_dev_desc_t *dev_desc = NULL;
116         int ret;
117         char bufread[50];
118
119         mmc = find_mmc_device(0);
120         if(mmc) {
121                 ret = mmc_init(mmc);
122                 if(ret < 0){
123                         debugf("mmc init failed %d\n", ret);
124                         return -1;
125                 }
126         } else {
127                 debugf("no mmc card found\n");
128                 return -1;
129         }
130
131         dev_desc = &mmc->block_dev;
132         if(dev_desc==NULL){
133                 debugf("no mmc block device found\n");
134                 return -1;
135         }
136
137         ret = fat_register_device(dev_desc, 1);
138         if(ret < 0) {
139                 debugf("fat regist fail %d\n", ret);
140                 return -1;
141         }
142
143         ret = file_fat_detectfs();
144         if(ret) {
145                 debugf("detect fs failed\n");
146                 return -1;
147         }
148
149         return 0;
150 }
151
152 void write_mem_to_mmc(char *path, char *filename,
153         void *memaddr, unsigned long memsize)
154 {
155         int ret;
156
157         if (path) {
158                 do {} while (0); /* TODO: jianjun.he */
159         }
160
161         debugf("writing 0x%lx bytes to sd file %s\n",
162                 memsize, filename);
163         lcd_printf("writing 0x%lx bytes to sd file %s\n", memsize, filename);
164         lcd_display();
165         ret = file_fat_write(filename, memaddr, memsize);
166         if (ret <= 0) {
167                 debugf("sd file write error %d\n", ret);
168         }
169
170         return;
171 }
172
173 extern unsigned check_reboot_mode(void);
174
175
176 static size_t get_elfhdr_size(int nphdr)
177 {
178         size_t elfhdr_len;
179
180         elfhdr_len = sizeof(struct elfhdr) +
181                 (nphdr + 1) * sizeof(struct elf_phdr);
182 #if SETUP_NOTE
183         elfhdr_len += ((sizeof(struct elf_note)) +
184                 roundup(sizeof(CORE_STR), 4)) * 3 +
185                 roundup(sizeof(struct elf_prstatus), 4) +
186                 roundup(sizeof(struct elf_prpsinfo), 4) +
187                 roundup(sizeof(struct task_struct), 4);
188 #endif
189         elfhdr_len = PAGE_ALIGN(elfhdr_len); //why?
190
191         return elfhdr_len;
192 }
193
194 #if SETUP_NOTE
195 static int notesize(struct memelfnote *en)
196 {
197         int sz;
198
199         sz = sizeof(struct elf_note);
200         sz += roundup((strlen(en->name) + 1), 4);
201         sz += roundup(en->datasz, 4);
202
203         return sz;
204 }
205
206 static char *storenote(struct memelfnote *men, char *bufp)
207 {
208         struct elf_note en;
209
210 #define DUMP_WRITE(addr,nr) do { memcpy(bufp,addr,nr); bufp += nr; } while(0)
211
212         en.n_namesz = strlen(men->name) + 1;
213         en.n_descsz = men->datasz;
214         en.n_type = men->type;
215
216         DUMP_WRITE(&en, sizeof(en));
217         DUMP_WRITE(men->name, en.n_namesz);
218
219         /* XXX - cast from long long to long to avoid need for libgcc.a */
220         bufp = (char*) roundup((unsigned long)bufp,4);
221         DUMP_WRITE(men->data, men->datasz);
222         bufp = (char*) roundup((unsigned long)bufp,4);
223
224 #undef DUMP_WRITE
225
226         return bufp;
227 }
228
229 #endif
230
231 static void sysdump_fill_core_hdr(struct pt_regs *regs,
232                                                 struct sysdump_mem *sysmem, int mem_num,
233                                                 char *bufp, int nphdr, int dataoff)
234 {
235 #if 0
236         struct elf_prstatus prstatus;   /* NT_PRSTATUS */
237         struct elf_prpsinfo prpsinfo;   /* NT_PRPSINFO */
238 #endif
239         struct elf_phdr *nhdr, *phdr;
240         struct elfhdr *elf;
241         struct memelfnote notes[3];
242         off_t offset = 0;
243         int i;
244
245         /* setup ELF header */
246         elf = (struct elfhdr *) bufp;
247         bufp += sizeof(struct elfhdr); //printk("sizeof(struct elfhdr): %d\n");
248         offset += sizeof(struct elfhdr); //printk("sizeof(struct elfhdr): %d\n");
249         memcpy(elf->e_ident, ELFMAG, SELFMAG); //printk("ELFMAG: %s, SELFMAG:%d\n", ELFMAG, SELFMAG);
250         elf->e_ident[EI_CLASS]  = ELF_CLASS;//printk("EI_CLASS:%d, ELF_CLASS: %d", EI_CLASS, ELF_CLASS);
251         elf->e_ident[EI_DATA]   = ELF_DATA;//printk("EI_DATA:%");
252         elf->e_ident[EI_VERSION]= EV_CURRENT;
253         elf->e_ident[EI_OSABI] = ELF_OSABI;
254         memset(elf->e_ident+EI_PAD, 0, EI_NIDENT-EI_PAD);
255         elf->e_type     = ET_CORE;
256         elf->e_machine  = ELF_ARCH;
257         elf->e_version  = EV_CURRENT;
258         elf->e_entry    = 0;
259         elf->e_phoff    = sizeof(struct elfhdr);
260         elf->e_shoff    = 0;
261         elf->e_flags    = ELF_CORE_EFLAGS;
262         elf->e_ehsize   = sizeof(struct elfhdr);
263         elf->e_phentsize= sizeof(struct elf_phdr);
264         elf->e_phnum    = nphdr;
265         elf->e_shentsize= 0;
266         elf->e_shnum    = 0;
267         elf->e_shstrndx = 0;
268
269         /* setup ELF PT_NOTE program header */
270         nhdr = (struct elf_phdr *) bufp;
271         bufp += sizeof(struct elf_phdr);
272         offset += sizeof(struct elf_phdr);
273         nhdr->p_type    = PT_NOTE;
274         nhdr->p_offset  = 0;
275         nhdr->p_vaddr   = 0;
276         nhdr->p_paddr   = 0;
277         nhdr->p_filesz  = 0;
278         nhdr->p_memsz   = 0;
279         nhdr->p_flags   = 0;
280         nhdr->p_align   = 0;
281
282         /* setup ELF PT_LOAD program header for every area */
283         for (i = 0; i < mem_num; i++) {
284                 phdr = (struct elf_phdr *) bufp;
285                 bufp += sizeof(struct elf_phdr);
286                 offset += sizeof(struct elf_phdr);
287
288                 phdr->p_type    = PT_LOAD;
289                 phdr->p_flags   = PF_R|PF_W|PF_X;
290                 phdr->p_offset  = dataoff;
291                 phdr->p_vaddr   = sysmem[i].vaddr;
292                 phdr->p_paddr   = sysmem[i].paddr;
293                 phdr->p_filesz  = phdr->p_memsz = sysmem[i].size;
294                 phdr->p_align   = 0;//PAGE_SIZE;
295                 dataoff += sysmem[i].size;
296         }
297 #if SETUP_NOTE
298         /*
299          * Set up the notes in similar form to SVR4 core dumps made
300          * with info from their /proc.
301          */
302         nhdr->p_offset  = offset;
303
304         /* set up the process status */
305         notes[0].name = CORE_STR;
306         notes[0].type = NT_PRSTATUS;
307         notes[0].datasz = sizeof(struct elf_prstatus);
308         notes[0].data = &prstatus;
309
310         memset(&prstatus, 0, sizeof(struct elf_prstatus));
311         //fill_prstatus(&prstatus, current, 0);
312         //if (regs)
313         //      memcpy(&prstatus.pr_reg, regs, sizeof(*regs));
314         //else
315         //      crash_setup_regs((struct pt_regs *)&prstatus.pr_reg, NULL);
316
317         nhdr->p_filesz  = notesize(&notes[0]);
318         bufp = storenote(&notes[0], bufp);
319
320         /* set up the process info */
321         notes[1].name   = CORE_STR;
322         notes[1].type   = NT_PRPSINFO;
323         notes[1].datasz = sizeof(struct elf_prpsinfo);
324         notes[1].data   = &prpsinfo;
325
326         memset(&prpsinfo, 0, sizeof(struct elf_prpsinfo));
327         //fill_psinfo(&prpsinfo, current, current->mm);
328
329         strcpy(prpsinfo.pr_fname, "vmlinux");
330         //strncpy(prpsinfo.pr_psargs, saved_command_line, ELF_PRARGSZ);
331
332         nhdr->p_filesz  += notesize(&notes[1]);
333         bufp = storenote(&notes[1], bufp);
334
335         /* set up the task structure */
336         notes[2].name   = CORE_STR;
337         notes[2].type   = NT_TASKSTRUCT;
338         notes[2].datasz = sizeof(struct task_struct);
339         notes[2].data   = current;
340
341         printk("%s: data size is %d, data addr is %p",__func__,notes[2].datasz,notes[2].data);
342
343         nhdr->p_filesz  += notesize(&notes[2]);
344         bufp = storenote(&notes[2], bufp);
345 #endif
346         return;
347 } /* end elf_kcore_store_hdr() */
348
349 #define PROD_PART "prodnv"
350 int sysdump_flag_check(void)
351 {
352         char sysdump_buf[200]={0};
353
354         memset(sysdump_buf,0x0,200);
355         if(!do_fs_file_read(PROD_PART, "sysdump_flag", sysdump_buf,200))
356                 debugf("file: sysdump_flag is exist\n");
357         else {
358                 debugf("file: sysdump_flag is not exist\n");
359 #ifdef SYSDUMP_BYPASS
360                 return -1;
361 #else
362                 return 1;
363 #endif
364         }
365
366         if(!strncmp(sysdump_buf, "on", 2))
367                 return 1;
368
369         return -1;
370 }
371 char *rstmode[] = {
372         "fastboot",             // 0x77665500           FASTBOOT_MODE
373         "manual dump",             // 0x01              UNDEFINE_MODE
374         "recovery",             // 0x77665502           RECOVERY_MODE
375         "normal",               // 0x77665503           NORMAL_MODE
376         "alarm",                // 0x77665504           ALARM_MODE
377         "sleep",                // 0x77665505           SLEEP_MODE
378         "watchdogtimeout",             // 0x77665506            WATCHDOG_REBOOT
379         "framework crash",              // 0x77665507           SPECIAL_MODE
380         "manual dump",        // 0x77665508             UNKNOW_REBOOT_MODE
381         "kernel crash",                // 0x77665509            PANIC_REBOOT
382         "calibration",          // 0x7766550a           CALIBRATION_MODE
383 };
384
385 #define GET_RST_MODE(x) rstmode[(((x)&0x0F) < 0x0b) ? ((x)&0x0F) : 1]
386
387 #ifndef CONFIG_EMMC_BOOT
388 /*Copy the data saved in nand flash to ram*/
389 int read_nand_to_ram( struct mtd_info *mtd, loff_t paddr, unsigned int size, unsigned char *buf)
390 {
391         int ret = 0;
392         unsigned int retlen = 0;
393         loff_t read_addr = 0;
394         unsigned char *read_buf = NULL;
395         unsigned int readsize = 0;
396
397         debugf("%s, read 0x%.8x:0x%.8x buf: 0x%.8x\n", __func__, (unsigned int)paddr, size, buf);
398         for(read_addr = paddr, read_buf = buf; read_addr < (paddr + size); read_addr += readsize, read_buf += readsize) {
399                 readsize = (paddr + size - read_addr) > mtd->erasesize ? mtd->erasesize : (paddr + size - read_addr);
400                 if(mtd->block_isbad(mtd, read_addr) == 1) {//if met bad block, we just fill it with 0x5a
401                         memset(read_buf, 0x5a, readsize);
402                         continue;
403                 }
404
405                 ret = mtd->read(mtd, read_addr, readsize, &retlen, read_buf);
406                 if(ret != 0 && retlen != readsize) {
407                         printf("%s, read addr: 0x%.8x len: 0x%.8x 's value err, ret: %d, retlen: 0x%.8x\n",\
408                          __func__, (unsigned int)read_addr, readsize, ret, retlen);
409                         lcd_printf("\nRead nand flash 0x%.8x error, you can dump it use download tools again!\n", read_addr);
410                         lcd_display();
411                         break;
412                 }
413         }
414         return ret;
415 }
416
417 /*dump the data saved in nand flash to sdcard when needed*/
418 void mtd_dump(void)
419 {
420         int ret = 0;
421         unsigned int write_len = 0, write_addr = 0;
422         char *buf = NULL;
423         unsigned int part_len = 0x8000000;//The size of each ubipac-part file
424         int loop = 0;
425         char fname[72];
426         struct mtd_info *mtd = NULL;
427
428         buf = SCRATCH_ADDR;//After dump memory to sdcard, we suppose the whole memory except u-boot used are avaliable.
429         mtd = get_mtd_device_nm(UBIPAC_PART);
430         if(mtd == NULL) {
431                 printf("Can't get the mtd part: %s\n", UBIPAC_PART);
432                 return;
433         }
434
435         debugf("Begin to dump 0x%.8x ubipac to sdcard!\n", mtd->size);
436         for(write_addr = 0; write_addr < mtd->size; write_addr += write_len, loop++)
437         {
438                 write_len = (mtd->size - write_addr) > part_len ? part_len : (mtd->size - write_addr);
439                 debugf("begin to read 0x%.8x value to ubipac%d\n", write_len, loop);
440                 memset(buf, 0, write_len);
441                 ret = read_nand_to_ram(mtd, (loff_t)(write_addr), write_len, buf);
442                 if(ret != 0) {
443                         printf("%s, read ubipac%d error, the ret is %d\n", __func__, loop, ret);
444                         break;
445                 }
446                 debugf("read ubipac%d end\n", loop);
447
448                 memset(fname, 0, 72);
449                 sprintf(fname, "ubipac%d", loop);
450                 write_mem_to_mmc(NULL, fname, buf, write_len);
451                 debugf("write ubipac%d end\n", loop);
452         }
453         put_mtd_device(mtd);
454 }
455 #endif
456
457
458 void write_sysdump_before_boot(int rst_mode)
459 {
460         int i, j, len;
461         char fnbuf[72], *path;
462         struct rtc_time rtc;
463         char *waddr;
464         struct sysdump_mem *mem;
465         struct sysdump_info *infop = (struct sysdump_info *)SPRD_SYSDUMP_MAGIC;
466
467         struct sysdump_mem sprd_dump_mem[] = {
468                 {
469                         .paddr = CONFIG_PHYS_OFFSET,
470                         .vaddr = PAGE_OFFSET,
471                         .soff = 0xffffffff,
472                         .size = REAL_SDRAM_SIZE,
473                         .type = SYSDUMP_RAM,
474                 },
475         };
476
477         int sprd_dump_mem_num = 1;
478
479         debugf("rst_mode:0x%x, Check if need to write sysdump info of 0x%08lx to file...\t", rst_mode,
480                 SPRD_SYSDUMP_MAGIC);
481
482         if ((rst_mode == WATCHDOG_REBOOT) || (rst_mode == UNKNOW_REBOOT_MODE) || (rst_mode == EXT_RSTN_REBOOT_MODE) || \
483                 ((rst_mode == PANIC_REBOOT) && !memcmp(infop->magic, SYSDUMP_MAGIC, sizeof(infop->magic))) || (rst_mode == SPECIAL_MODE) ) {
484                 debugf("\n");
485
486                 memset(infop->magic, 0, sizeof(infop->magic));
487
488                 if(-1 == sysdump_flag_check()) {
489                         debugf("skip sysdump because sysdump_flag is close.\n");
490                         goto FINISH;
491                 }
492                 MMU_DisableIDCM();
493                 if (init_mmc_fat())
494                         goto FINISH;
495
496                 /* display on screen */
497                 display_writing_sysdump();
498                 #define CONSOLE_COLOR_RED (0x1f<<11)
499                 #define CONSOLE_COLOR_GREEN 0x07e0
500                 lcd_setfgcolor(CONSOLE_COLOR_GREEN);
501                 lcd_printf("\nReset mode: %s\n\n",GET_RST_MODE(rst_mode));
502                 lcd_setfgcolor(CONSOLE_COLOR_RED);
503                 lcd_display();
504
505                 if ((rst_mode == WATCHDOG_REBOOT) || (rst_mode == UNKNOW_REBOOT_MODE) || (rst_mode == EXT_RSTN_REBOOT_MODE) || (rst_mode == SPECIAL_MODE)) {
506                         infop->dump_path[0] = '\0';
507                         infop->mem_num = sprd_dump_mem_num;
508                         infop->dump_mem_paddr = (unsigned long)sprd_dump_mem;
509                         strcpy(infop->time, "hw_watchdog");
510                         infop->elfhdr_size = get_elfhdr_size(infop->mem_num);
511                         infop->crash_key = 0;
512
513                         sysdump_fill_core_hdr(NULL,
514                                         sprd_dump_mem,
515                                         sprd_dump_mem_num,
516                                         (char *)infop + sizeof(*infop),
517                                         infop->mem_num + 1,
518                                         infop->elfhdr_size);
519                 }
520
521                 if (strlen(infop->dump_path))
522                         path = infop->dump_path;
523                 else
524                         path = NULL;
525
526                 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, 0);
527                 write_mem_to_mmc(path, fnbuf,
528                         (char *)infop + sizeof(*infop), infop->elfhdr_size);
529
530 #if 1 /* TODO: jianjun.he */
531                 mem = (struct sysdump_mem *)infop->dump_mem_paddr;
532                 for (i = 0; i < infop->mem_num; i++) {
533                         if (0xffffffff != mem[i].soff)
534                                 waddr = (char *)infop + sizeof(*infop) + 
535                                                 infop->elfhdr_size + mem[i].soff;
536                         else
537                                 waddr = mem[i].paddr;
538
539                 #ifdef CONFIG_RAMDUMP_NO_SPLIT
540                                 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_0x%8.8x-0x%8.8x_dump.lst", i + 1, mem[i].paddr, mem[i].paddr + mem[i].size -1);
541                                 write_mem_to_mmc(path, fnbuf, waddr, mem[i].size);
542                 #else
543                         if (mem[i].size <= SZ_8M) {
544                                 sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, /*infop->time,*/ i + 1);
545                                 write_mem_to_mmc(path, fnbuf, waddr, mem[i].size);
546                         } else {
547                                 for (j = 0; j < mem[i].size / SZ_8M; j++) {
548                                         sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_%03d",
549                                                 /*infop->time,*/ i + 1, j);
550                                         write_mem_to_mmc(path, fnbuf, waddr + j * SZ_8M, SZ_8M);
551                                 }
552
553                                 if (mem[i].size % SZ_8M) {
554                                         sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT"_%03d",
555                                                 /*infop->time,*/ i + 1, j);
556                                         write_mem_to_mmc(path, fnbuf, waddr + j * SZ_8M,
557                                                                         (mem[i].size % SZ_8M));
558                                 }
559                         }
560                 #endif
561                 }
562 #else
563                 for (i = 0; i < infop->mem_num; i++) {
564                         sprintf(fnbuf, SYSDUMP_CORE_NAME_FMT, /*infop->time,*/ i + 1);
565                         write_mem_to_mmc(path, fnbuf, mem[i].paddr, mem[i].size);
566                 }
567 #endif
568
569 #ifndef CONFIG_EMMC_BOOT
570                 lcd_printf("\nBegin to dump nand flash:\n");
571                 lcd_display();
572                 mtd_dump();
573 #endif
574                 debugf("\nwriting done.\nPress any key to continue...");
575                 lcd_printf("\nWriting done.\nPress any key (Exp power key) to continue...");
576                 lcd_display();
577                 wait_for_keypress();
578         } else
579                 debugf("no need.\n");
580
581 FINISH:
582         return;
583 }
584
585
586
587