reboot-reason.c 9.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386
  1. #include <linux/kobject.h>
  2. #include <linux/string.h>
  3. #include <linux/sysfs.h>
  4. #include <linux/init.h>
  5. #include <linux/sched.h>
  6. #include <linux/module.h>
  7. #include <linux/proc_fs.h>
  8. #include <linux/seq_file.h>
  9. #include <linux/delay.h>
  10. #include <linux/mm.h>
  11. #include <linux/sched.h>
  12. #include <asm/stacktrace.h>
  13. #include <asm/memory.h>
  14. #include <asm/traps.h>
  15. #include <linux/elf.h>
  16. #include <mach/wd_api.h>
  17. #include <smp.h>
  18. #include <mt-plat/aee.h>
  19. #include <mrdump.h>
  20. #include "aee-common.h"
  21. #define RR_PROC_NAME "reboot-reason"
  22. static struct proc_dir_entry *aee_rr_file;
  23. #define WDT_NORMAL_BOOT 0
  24. #define WDT_HW_REBOOT 1
  25. #define WDT_SW_REBOOT 2
  26. enum boot_reason_t {
  27. BR_POWER_KEY = 0,
  28. BR_USB,
  29. BR_RTC,
  30. BR_WDT,
  31. BR_WDT_BY_PASS_PWK,
  32. BR_TOOL_BY_PASS_PWK,
  33. BR_2SEC_REBOOT,
  34. BR_UNKNOWN,
  35. BR_KE_REBOOT
  36. };
  37. char boot_reason[][16] = { "XXXXXX", "XXXXXXX", "XXX", "XXX",
  38. "XXXXXX", "XXXXXXXXXXX", "XXXX", "XXXXXX", "XXXXXX" };
  39. int __weak aee_rr_reboot_reason_show(struct seq_file *m, void *v)
  40. {
  41. seq_puts(m, "mtk_ram_console not enabled.");
  42. return 0;
  43. }
  44. static int aee_rr_reboot_reason_proc_open(struct inode *inode, struct file *file)
  45. {
  46. return single_open(file, aee_rr_reboot_reason_show, NULL);
  47. }
  48. static const struct file_operations aee_rr_reboot_reason_proc_fops = {
  49. .open = aee_rr_reboot_reason_proc_open,
  50. .read = seq_read,
  51. .llseek = seq_lseek,
  52. .release = single_release,
  53. };
  54. void aee_rr_proc_init(struct proc_dir_entry *aed_proc_dir)
  55. {
  56. aee_rr_file = proc_create(RR_PROC_NAME,
  57. 0444, aed_proc_dir, &aee_rr_reboot_reason_proc_fops);
  58. if (aee_rr_file == NULL)
  59. LOGE("%s: Can't create rr proc entry\n", __func__);
  60. }
  61. EXPORT_SYMBOL(aee_rr_proc_init);
  62. void aee_rr_proc_done(struct proc_dir_entry *aed_proc_dir)
  63. {
  64. remove_proc_entry(RR_PROC_NAME, aed_proc_dir);
  65. }
  66. EXPORT_SYMBOL(aee_rr_proc_done);
  67. /* define /sys/bootinfo/powerup_reason */
  68. static ssize_t powerup_reason_show(struct kobject *kobj, struct kobj_attribute *attr, char *buf)
  69. {
  70. int g_boot_reason = 0;
  71. char *br_ptr;
  72. br_ptr = strstr(saved_command_line, "boot_reason=");
  73. if (br_ptr != 0) {
  74. /* get boot reason */
  75. g_boot_reason = br_ptr[12] - '0';
  76. LOGE("g_boot_reason=%d\n", g_boot_reason);
  77. #ifdef CONFIG_MTK_RAM_CONSOLE
  78. if (aee_rr_last_fiq_step() != 0)
  79. g_boot_reason = BR_KE_REBOOT;
  80. #endif
  81. return sprintf(buf, "%s\n", boot_reason[g_boot_reason]);
  82. } else
  83. return 0;
  84. }
  85. static struct kobj_attribute powerup_reason_attr = __ATTR_RO(powerup_reason);
  86. struct kobject *bootinfo_kobj;
  87. EXPORT_SYMBOL(bootinfo_kobj);
  88. static struct attribute *bootinfo_attrs[] = {
  89. &powerup_reason_attr.attr,
  90. NULL
  91. };
  92. static struct attribute_group bootinfo_attr_group = {
  93. .attrs = bootinfo_attrs,
  94. };
  95. int ksysfs_bootinfo_init(void)
  96. {
  97. int error;
  98. bootinfo_kobj = kobject_create_and_add("bootinfo", NULL);
  99. if (!bootinfo_kobj)
  100. return -ENOMEM;
  101. error = sysfs_create_group(bootinfo_kobj, &bootinfo_attr_group);
  102. if (error)
  103. kobject_put(bootinfo_kobj);
  104. return error;
  105. }
  106. void ksysfs_bootinfo_exit(void)
  107. {
  108. kobject_put(bootinfo_kobj);
  109. }
  110. /* end sysfs bootinfo */
  111. static inline unsigned int get_linear_memory_size(void)
  112. {
  113. return (unsigned long)high_memory - PAGE_OFFSET;
  114. }
  115. static char nested_panic_buf[1024];
  116. int aee_nested_printf(const char *fmt, ...)
  117. {
  118. va_list args;
  119. static int total_len;
  120. va_start(args, fmt);
  121. total_len += vsnprintf(nested_panic_buf, sizeof(nested_panic_buf), fmt, args);
  122. va_end(args);
  123. aee_sram_fiq_log(nested_panic_buf);
  124. return total_len;
  125. }
  126. static void print_error_msg(int len)
  127. {
  128. static char error_msg[][50] = { "Bottom unaligned", "Bottom out of kernel addr",
  129. "Top out of kernel addr", "Buf len not enough"
  130. };
  131. int tmp = (-len) - 1;
  132. aee_sram_fiq_log(error_msg[tmp]);
  133. }
  134. /*save stack as binary into buf,
  135. *return value
  136. -1: bottom unaligned
  137. -2: bottom out of kernel addr space
  138. -3 top out of kernel addr addr
  139. -4: buff len not enough
  140. >0: used length of the buf
  141. */
  142. int aee_dump_stack_top_binary(char *buf, int buf_len, unsigned long bottom, unsigned long top)
  143. {
  144. /*should check stack address in kernel range */
  145. if (bottom & 3)
  146. return -1;
  147. if (!((bottom >= (PAGE_OFFSET + THREAD_SIZE)) &&
  148. (bottom <= (PAGE_OFFSET + get_linear_memory_size())))) {
  149. return -2;
  150. }
  151. if (!((top >= (PAGE_OFFSET + THREAD_SIZE)) &&
  152. (top <= (PAGE_OFFSET + get_linear_memory_size())))) {
  153. return -3;
  154. }
  155. if (buf_len < top - bottom)
  156. return -4;
  157. memcpy((void *)buf, (void *)bottom, top - bottom);
  158. return top - bottom;
  159. }
  160. /* extern void mt_fiq_printf(const char *fmt, ...); */
  161. void *aee_excp_regs;
  162. static atomic_t nested_panic_time = ATOMIC_INIT(0);
  163. #ifdef __aarch64__
  164. #define FORMAT_LONG "%016lx "
  165. #else
  166. #define FORMAT_LONG "%08lx "
  167. #endif
  168. inline void aee_print_regs(struct pt_regs *regs)
  169. {
  170. int i;
  171. aee_nested_printf("[pt_regs]");
  172. for (i = 0; i < ELF_NGREG; i++)
  173. aee_nested_printf(FORMAT_LONG, ((unsigned long *)regs)[i]);
  174. aee_nested_printf("\n");
  175. }
  176. #define AEE_MAX_EXCP_FRAME 32
  177. inline void aee_print_bt(struct pt_regs *regs)
  178. {
  179. int i;
  180. unsigned long high, bottom, fp;
  181. struct stackframe cur_frame;
  182. struct pt_regs *excp_regs;
  183. bottom = regs->reg_sp;
  184. if (!virt_addr_valid(bottom)) {
  185. aee_nested_printf("invalid sp[%lx]\n", regs);
  186. return;
  187. }
  188. high = ALIGN(bottom, THREAD_SIZE);
  189. cur_frame.fp = regs->reg_fp;
  190. cur_frame.pc = regs->reg_pc;
  191. cur_frame.sp = regs->reg_sp;
  192. for (i = 0; i < AEE_MAX_EXCP_FRAME; i++) {
  193. fp = cur_frame.fp;
  194. if ((fp < bottom) || (fp >= (high + THREAD_SIZE))) {
  195. if (fp != 0)
  196. aee_nested_printf("fp(%lx)", fp);
  197. break;
  198. }
  199. unwind_frame(&cur_frame);
  200. if (!((cur_frame.pc >= (PAGE_OFFSET + THREAD_SIZE))
  201. && virt_addr_valid(cur_frame.pc)))
  202. break;
  203. if (in_exception_text(cur_frame.pc)) {
  204. #ifdef __aarch64__
  205. /* work around for unknown reason do_mem_abort stack abnormal */
  206. excp_regs = (void *)(cur_frame.fp + 0x10 + 0xa0);
  207. unwind_frame(&cur_frame); /* skip do_mem_abort & el1_da */
  208. #else
  209. excp_regs = (void *)(cur_frame.fp + 4);
  210. #endif
  211. cur_frame.pc = excp_regs->reg_pc;
  212. }
  213. aee_nested_printf("%p, ", (void *)cur_frame.pc);
  214. }
  215. aee_nested_printf("\n");
  216. }
  217. inline int aee_nested_save_stack(struct pt_regs *regs)
  218. {
  219. int len = 0;
  220. if (!virt_addr_valid(regs->reg_sp))
  221. return -1;
  222. aee_nested_printf("[%lx %lx]\n", regs->reg_sp, regs->reg_sp + 256);
  223. len = aee_dump_stack_top_binary(nested_panic_buf, sizeof(nested_panic_buf),
  224. regs->reg_sp, regs->reg_sp + 256);
  225. if (len > 0)
  226. aee_sram_fiq_save_bin(nested_panic_buf, len);
  227. else
  228. print_error_msg(len);
  229. return len;
  230. }
  231. int aee_in_nested_panic(void)
  232. {
  233. return (atomic_read(&nested_panic_time) &&
  234. ((aee_rr_curr_fiq_step() & ~(AEE_FIQ_STEP_KE_NESTED_PANIC - 1)) ==
  235. AEE_FIQ_STEP_KE_NESTED_PANIC));
  236. }
  237. static inline void aee_rec_step_nested_panic(int step)
  238. {
  239. if (step < 64)
  240. aee_rr_rec_fiq_step(AEE_FIQ_STEP_KE_NESTED_PANIC + step);
  241. }
  242. asmlinkage void aee_stop_nested_panic(struct pt_regs *regs)
  243. {
  244. struct thread_info *thread = current_thread_info();
  245. int len = 0;
  246. int timeout = 1000000;
  247. int res = 0, cpu = 0;
  248. struct wd_api *wd_api = NULL;
  249. struct pt_regs *excp_regs = NULL;
  250. int prev_fiq_step = aee_rr_curr_fiq_step();
  251. /* everytime enter nested_panic flow, add 8 */
  252. static int step_base = -8;
  253. step_base = step_base < 48 ? step_base + 8 : 56;
  254. aee_rec_step_nested_panic(step_base);
  255. local_irq_disable();
  256. aee_rec_step_nested_panic(step_base + 1);
  257. cpu = get_HW_cpuid();
  258. aee_rec_step_nested_panic(step_base + 2);
  259. /*nested panic may happens more than once on many/single cpus */
  260. if (atomic_read(&nested_panic_time) < 3)
  261. aee_nested_printf("\nCPU%dpanic%d@%d\n", cpu, nested_panic_time, prev_fiq_step);
  262. atomic_inc(&nested_panic_time);
  263. switch (atomic_read(&nested_panic_time)) {
  264. case 2:
  265. aee_print_regs(regs);
  266. aee_nested_printf("backtrace:");
  267. aee_print_bt(regs);
  268. break;
  269. /* must guarantee Only one cpu can run here */
  270. /* first check if thread valid */
  271. case 1:
  272. if (virt_addr_valid(thread) && virt_addr_valid(thread->regs_on_excp)) {
  273. excp_regs = thread->regs_on_excp;
  274. } else {
  275. /* if thread invalid, which means wrong sp or thread_info corrupted,
  276. check global aee_excp_regs instead */
  277. aee_nested_printf("invalid thread [%lx], excp_regs [%lx]\n", thread,
  278. aee_excp_regs);
  279. excp_regs = aee_excp_regs;
  280. }
  281. aee_nested_printf("Nested panic\n");
  282. if (excp_regs) {
  283. aee_nested_printf("Previous\n");
  284. aee_print_regs(excp_regs);
  285. }
  286. aee_nested_printf("Current\n");
  287. aee_print_regs(regs);
  288. /*should not print stack info. this may overwhelms ram console used by fiq */
  289. if (0 != in_fiq_handler()) {
  290. aee_nested_printf("in fiq handler\n");
  291. } else {
  292. /*Dump first panic stack */
  293. aee_nested_printf("Previous\n");
  294. if (excp_regs) {
  295. len = aee_nested_save_stack(excp_regs);
  296. aee_nested_printf("\nbacktrace:");
  297. aee_print_bt(excp_regs);
  298. }
  299. /*Dump second panic stack */
  300. aee_nested_printf("Current\n");
  301. if (virt_addr_valid(regs)) {
  302. len = aee_nested_save_stack(regs);
  303. aee_nested_printf("\nbacktrace:");
  304. aee_print_bt(regs);
  305. }
  306. }
  307. aee_rec_step_nested_panic(step_base + 5);
  308. ipanic_recursive_ke(regs, excp_regs, cpu);
  309. aee_rec_step_nested_panic(step_base + 6);
  310. /* we donot want a FIQ after this, so disable hwt */
  311. res = get_wd_api(&wd_api);
  312. if (res)
  313. aee_nested_printf("get_wd_api error\n");
  314. else
  315. wd_api->wd_aee_confirm_hwreboot();
  316. aee_rec_step_nested_panic(step_base + 7);
  317. break;
  318. default:
  319. break;
  320. }
  321. /* waiting for the WDT timeout */
  322. while (1) {
  323. /* output to UART directly to avoid printk nested panic */
  324. /* mt_fiq_printf("%s hang here%d\t", __func__, i++); */
  325. while (timeout--)
  326. udelay(1);
  327. timeout = 1000000;
  328. }
  329. }