mrdump_full.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564
  1. #include <stdarg.h>
  2. #include <linux/delay.h>
  3. #include <linux/module.h>
  4. #include <linux/kernel.h>
  5. #include <linux/mm.h>
  6. #include <mt-plat/aee.h>
  7. #include <linux/elf.h>
  8. #include <linux/elfcore.h>
  9. #include <linux/kallsyms.h>
  10. #include <linux/memblock.h>
  11. #include <linux/miscdevice.h>
  12. #include <mt-plat/mtk_ram_console.h>
  13. #include <linux/reboot.h>
  14. #include <linux/stacktrace.h>
  15. #include <linux/vmalloc.h>
  16. #include <linux/elfcore.h>
  17. #include <linux/kexec.h>
  18. #include <asm/pgtable.h>
  19. #include <asm/processor.h>
  20. #if defined(CONFIG_FIQ_GLUE)
  21. #include <asm/fiq_smp_call.h>
  22. #endif
  23. #include <smp.h>
  24. #include <mrdump.h>
  25. #include <linux/kdebug.h>
  26. #include "mrdump_private.h"
  27. #define KEXEC_NOTE_HEAD_BYTES ALIGN(sizeof(struct elf_note), 4)
  28. #define KEXEC_CORE_NOTE_NAME "CORE"
  29. #define KEXEC_CORE_NOTE_NAME_BYTES ALIGN(sizeof(KEXEC_CORE_NOTE_NAME), 4)
  30. #define KEXEC_CORE_NOTE_DESC_BYTES ALIGN(sizeof(struct elf_prstatus), 4)
  31. #define KEXEC_NOTE_BYTES ((KEXEC_NOTE_HEAD_BYTES * 2) + \
  32. KEXEC_CORE_NOTE_NAME_BYTES + \
  33. KEXEC_CORE_NOTE_DESC_BYTES)
  34. typedef u32 note_buf_t[KEXEC_NOTE_BYTES / 4];
  35. static int crashing_cpu;
  36. static note_buf_t __percpu *crash_notes;
  37. static bool mrdump_enable = 1;
  38. static int mrdump_output_device;
  39. static int mrdump_output_fstype;
  40. static unsigned long mrdump_output_lbaooo;
  41. static struct mrdump_control_block mrdump_cblock __attribute__((section (".mrdump")));
  42. static const struct mrdump_platform *mrdump_plat;
  43. static char mrdump_lk[12];
  44. static u32 *append_elf_note(u32 *buf, char *name, unsigned type, void *data,
  45. size_t data_len)
  46. {
  47. struct elf_note note;
  48. note.n_namesz = strlen(name) + 1;
  49. note.n_descsz = data_len;
  50. note.n_type = type;
  51. memcpy(buf, &note, sizeof(note));
  52. buf += (sizeof(note) + 3) / 4;
  53. memcpy(buf, name, note.n_namesz);
  54. buf += (note.n_namesz + 3) / 4;
  55. memcpy(buf, data, note.n_descsz);
  56. buf += (note.n_descsz + 3) / 4;
  57. return buf;
  58. }
  59. static void final_note(u32 *buf)
  60. {
  61. struct elf_note note;
  62. note.n_namesz = 0;
  63. note.n_descsz = 0;
  64. note.n_type = 0;
  65. memcpy(buf, &note, sizeof(note));
  66. }
  67. static void crash_save_cpu(struct pt_regs *regs, int cpu)
  68. {
  69. struct elf_prstatus prstatus;
  70. u32 *buf;
  71. if ((cpu < 0) || (cpu >= nr_cpu_ids))
  72. return;
  73. buf = (u32 *)per_cpu_ptr(crash_notes, cpu);
  74. if (!buf)
  75. return;
  76. memset(&prstatus, 0, sizeof(prstatus));
  77. prstatus.pr_pid = current->pid;
  78. elf_core_copy_kernel_regs((elf_gregset_t *)&prstatus.pr_reg, regs);
  79. buf = append_elf_note(buf, KEXEC_CORE_NOTE_NAME, NT_PRSTATUS,
  80. &prstatus, sizeof(prstatus));
  81. final_note(buf);
  82. }
  83. static void save_current_task(void)
  84. {
  85. int i;
  86. struct stack_trace trace;
  87. unsigned long stack_entries[16];
  88. struct task_struct *tsk;
  89. struct mrdump_crash_record *crash_record = &mrdump_cblock.crash_record;
  90. tsk = current_thread_info()->task;
  91. /* Grab kernel task stack trace */
  92. trace.nr_entries = 0;
  93. trace.max_entries = sizeof(stack_entries) / sizeof(stack_entries[0]);
  94. trace.entries = stack_entries;
  95. trace.skip = 1;
  96. save_stack_trace_tsk(tsk, &trace);
  97. for (i = 0; i < trace.nr_entries; i++) {
  98. int off = strlen(crash_record->backtrace);
  99. int plen = sizeof(crash_record->backtrace) - off;
  100. if (plen > 16) {
  101. snprintf(crash_record->backtrace + off, plen, "[<%p>] %pS\n",
  102. (void *)stack_entries[i], (void *)stack_entries[i]);
  103. }
  104. }
  105. }
  106. #if defined(CONFIG_FIQ_GLUE)
  107. static void aee_kdump_cpu_stop(void *arg, void *regs, void *svc_sp)
  108. {
  109. struct mrdump_crash_record *crash_record = &mrdump_cblock.crash_record;
  110. int cpu = 0;
  111. register int sp asm("sp");
  112. struct pt_regs *ptregs = (struct pt_regs *)regs;
  113. asm volatile("mov %0, %1\n\t"
  114. "mov fp, %2\n\t"
  115. : "=r" (sp)
  116. : "r" (svc_sp), "r" (ptregs->ARM_fp)
  117. );
  118. cpu = get_HW_cpuid();
  119. elf_core_copy_kernel_regs((elf_gregset_t *)&crash_record->cpu_regs[cpu], ptregs);
  120. crash_save_cpu((struct pt_regs *)regs, cpu);
  121. set_cpu_online(cpu, false);
  122. local_fiq_disable();
  123. local_irq_disable();
  124. __inner_flush_dcache_L1();
  125. while (1)
  126. cpu_relax();
  127. }
  128. static void __mrdump_reboot_stop_all(struct mrdump_crash_record *crash_record, int cpu)
  129. {
  130. int timeout;
  131. fiq_smp_call_function(aee_kdump_cpu_stop, NULL, 0);
  132. /* Wait up to two second for other CPUs to stop */
  133. timeout = 2 * USEC_PER_SEC;
  134. while (num_online_cpus() > 1 && timeout--)
  135. udelay(1);
  136. }
  137. #else
  138. /* Generic IPI support */
  139. static atomic_t waiting_for_crash_ipi;
  140. static void mrdump_stop_noncore_cpu(void *unused)
  141. {
  142. struct mrdump_crash_record *crash_record = &mrdump_cblock.crash_record;
  143. struct pt_regs regs;
  144. int cpu = get_HW_cpuid();
  145. mrdump_save_current_backtrace(&regs);
  146. elf_core_copy_kernel_regs((elf_gregset_t *)&crash_record->cpu_regs[cpu], &regs);
  147. crash_save_cpu((struct pt_regs *)&regs, cpu);
  148. local_fiq_disable();
  149. local_irq_disable();
  150. __inner_flush_dcache_L1();
  151. while (1)
  152. cpu_relax();
  153. }
  154. static void __mrdump_reboot_stop_all(struct mrdump_crash_record *crash_record, int cpu)
  155. {
  156. unsigned long msecs;
  157. atomic_set(&waiting_for_crash_ipi, num_online_cpus() - 1);
  158. smp_call_function(mrdump_stop_noncore_cpu, NULL, false);
  159. msecs = 1000; /* Wait at most a second for the other cpus to stop */
  160. while ((atomic_read(&waiting_for_crash_ipi) > 0) && msecs) {
  161. mdelay(1);
  162. msecs--;
  163. }
  164. if (atomic_read(&waiting_for_crash_ipi) > 0)
  165. pr_warn("Non-crashing CPUs did not react to IPI\n");
  166. }
  167. #endif
  168. static void __mrdump_reboot_va(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, va_list ap)
  169. {
  170. struct mrdump_crash_record *crash_record;
  171. int cpu;
  172. if (mrdump_enable != 1)
  173. pr_info("MT-RAMDUMP no enable");
  174. crash_record = &mrdump_cblock.crash_record;
  175. local_irq_disable();
  176. local_fiq_disable();
  177. #if defined(CONFIG_SMP)
  178. __mrdump_reboot_stop_all(crash_record, cpu);
  179. #endif
  180. cpu = get_HW_cpuid();
  181. crashing_cpu = cpu;
  182. crash_save_cpu(regs, cpu);
  183. elf_core_copy_kernel_regs((elf_gregset_t *)&crash_record->cpu_regs[cpu], regs);
  184. vsnprintf(crash_record->msg, sizeof(crash_record->msg), msg, ap);
  185. crash_record->fault_cpu = cpu;
  186. save_current_task();
  187. /* FIXME: Check reboot_mode is valid */
  188. crash_record->reboot_mode = reboot_mode;
  189. __inner_flush_dcache_all();
  190. if (reboot_mode == AEE_REBOOT_MODE_NESTED_EXCEPTION) {
  191. while (1)
  192. cpu_relax();
  193. }
  194. mrdump_print_crash(regs);
  195. mrdump_plat->reboot();
  196. }
  197. void aee_kdump_reboot(AEE_REBOOT_MODE reboot_mode, const char *msg, ...)
  198. {
  199. va_list ap;
  200. struct pt_regs regs;
  201. mrdump_save_current_backtrace(&regs);
  202. va_start(ap, msg);
  203. __mrdump_reboot_va(reboot_mode, &regs, msg, ap);
  204. /* No return anymore */
  205. va_end(ap);
  206. }
  207. void __mrdump_create_oops_dump(AEE_REBOOT_MODE reboot_mode, struct pt_regs *regs, const char *msg, ...)
  208. {
  209. va_list ap;
  210. va_start(ap, msg);
  211. __mrdump_reboot_va(reboot_mode, regs, msg, ap);
  212. va_end(ap);
  213. }
  214. static int mrdump_panic_create_dump(struct notifier_block *this, unsigned long event, void *ptr)
  215. {
  216. if (mrdump_enable) {
  217. if (test_taint(TAINT_DIE))
  218. aee_kdump_reboot(AEE_REBOOT_MODE_KERNEL_OOPS, "kernel Oops");
  219. else
  220. aee_kdump_reboot(AEE_REBOOT_MODE_KERNEL_PANIC, "kernel panic");
  221. } else
  222. pr_info("MT-RAMDUMP no enable");
  223. return NOTIFY_DONE;
  224. }
  225. static struct notifier_block mrdump_panic_blk = {
  226. .notifier_call = mrdump_panic_create_dump,
  227. };
  228. #if CONFIG_SYSFS
  229. static ssize_t dump_status_show(struct kobject *kobj, struct kobj_attribute *attr,
  230. char *page)
  231. {
  232. return 0;
  233. }
  234. static ssize_t mrdump_version_show(struct kobject *kobj, struct kobj_attribute *attr,
  235. char *buf)
  236. {
  237. return sprintf(buf, "%s\n", MRDUMP_GO_DUMP);
  238. }
  239. static ssize_t manual_dump_show(struct kobject *kobj, struct kobj_attribute *attr,
  240. char *buf)
  241. {
  242. return sprintf(buf, "Trigger manual dump with message, format \"manualdump:HelloWorld\"\n");
  243. }
  244. static ssize_t manual_dump_store(struct kobject *kobj, struct kobj_attribute *attr,
  245. const char *buf, size_t count)
  246. {
  247. if (strncmp(buf, "manualdump:", 11) == 0)
  248. aee_kdump_reboot(AEE_REBOOT_MODE_MANUAL_KDUMP, buf + 11);
  249. return count;
  250. }
  251. static struct kobj_attribute dump_status_attribute =
  252. __ATTR(dump_status, 0400, dump_status_show, NULL);
  253. static struct kobj_attribute mrdump_version_attribute =
  254. __ATTR(version, 0600, mrdump_version_show, NULL);
  255. static struct kobj_attribute manual_dump_attribute =
  256. __ATTR(manualdump, 0600, manual_dump_show, manual_dump_store);
  257. static struct attribute *attrs[] = {
  258. &dump_status_attribute.attr,
  259. &mrdump_version_attribute.attr,
  260. &manual_dump_attribute.attr,
  261. NULL,
  262. };
  263. static struct attribute_group attr_group = {
  264. .attrs = attrs,
  265. };
  266. #endif
  267. int __init mrdump_platform_init(const struct mrdump_platform *plat)
  268. {
  269. #if CONFIG_SYSFS
  270. struct kobject *kobj;
  271. #endif
  272. struct mrdump_machdesc *machdesc_p;
  273. memset(&mrdump_cblock, 0, sizeof(struct mrdump_control_block));
  274. mrdump_plat = plat;
  275. if (mrdump_plat == NULL) {
  276. mrdump_enable = 0;
  277. pr_err("%s: MT-RAMDUMP platform no init\n", __func__);
  278. return -EINVAL;
  279. }
  280. if (strcmp(mrdump_lk, MRDUMP_GO_DUMP) != 0) {
  281. mrdump_enable = 0;
  282. pr_err("%s: MT-RAMDUMP init failed, lk version %s not matched.\n", __func__, mrdump_lk);
  283. return -EINVAL;
  284. }
  285. memcpy(&mrdump_cblock.sig, MRDUMP_GO_DUMP, 8);
  286. /* move default enable MT-RAMDUMP to late_init (this function) */
  287. if (mrdump_enable) {
  288. mrdump_plat->hw_enable(mrdump_enable);
  289. __inner_flush_dcache_all();
  290. }
  291. machdesc_p = &mrdump_cblock.machdesc;
  292. machdesc_p->output_device = MRDUMP_DEV_EMMC;
  293. machdesc_p->output_fstype = MRDUMP_FS_EXT4;
  294. machdesc_p->nr_cpus = mrdump_enable ? NR_CPUS : 0;
  295. machdesc_p->page_offset = (uint64_t)PAGE_OFFSET;
  296. machdesc_p->high_memory = (uintptr_t)high_memory;
  297. machdesc_p->vmalloc_start = (uint64_t)VMALLOC_START;
  298. machdesc_p->vmalloc_end = (uint64_t)VMALLOC_END;
  299. machdesc_p->modules_start = (uint64_t)MODULES_VADDR;
  300. machdesc_p->modules_end = (uint64_t)MODULES_END;
  301. machdesc_p->phys_offset = (uint64_t)PHYS_OFFSET;
  302. machdesc_p->master_page_table = (uintptr_t)&swapper_pg_dir;
  303. /* Allocate memory for saving cpu registers. */
  304. crash_notes = alloc_percpu(note_buf_t);
  305. if (!crash_notes) {
  306. pr_err("MT-RAMDUMP: Memory allocation for saving cpu register failed\n");
  307. return -ENOMEM;
  308. }
  309. atomic_notifier_chain_register(&panic_notifier_list, &mrdump_panic_blk);
  310. #if CONFIG_SYSFS
  311. kobj = kset_find_obj(module_kset, KBUILD_MODNAME);
  312. if (kobj) {
  313. if (sysfs_create_group(kobj, &attr_group)) {
  314. pr_err("MT-RAMDUMP: sysfs create sysfs failed\n");
  315. return -ENOMEM;
  316. }
  317. } else {
  318. pr_err("MT-RAMDUMP: Cannot find module %s object\n", KBUILD_MODNAME);
  319. return -EINVAL;
  320. }
  321. #endif
  322. return 0;
  323. }
  324. static int param_set_mrdump_device(const char *val, const struct kernel_param *kp)
  325. {
  326. char strval[16], *strp;
  327. int eval;
  328. strlcpy(strval, val, sizeof(strval));
  329. strp = strstrip(strval);
  330. if (strcmp(strp, "null") == 0)
  331. eval = MRDUMP_DEV_NULL;
  332. else if (strcmp(strp, "sdcard") == 0)
  333. eval = MRDUMP_DEV_SDCARD;
  334. else if (strcmp(strp, "emmc") == 0)
  335. eval = MRDUMP_DEV_EMMC;
  336. else
  337. eval = MRDUMP_DEV_NULL;
  338. *(int *)kp->arg = eval;
  339. mrdump_cblock.machdesc.output_device = eval;
  340. __inner_flush_dcache_all();
  341. return 0;
  342. }
  343. static int param_get_mrdump_device(char *buffer, const struct kernel_param *kp)
  344. {
  345. char *dev;
  346. switch (mrdump_cblock.machdesc.output_device) {
  347. case MRDUMP_DEV_NULL:
  348. dev = "null";
  349. break;
  350. case MRDUMP_DEV_SDCARD:
  351. dev = "sdcard";
  352. break;
  353. case MRDUMP_DEV_EMMC:
  354. dev = "emmc";
  355. break;
  356. default:
  357. dev = "none(unknown)";
  358. break;
  359. }
  360. strcpy(buffer, dev);
  361. return strlen(dev);
  362. }
  363. static int param_set_mrdump_enable(const char *val, const struct kernel_param *kp)
  364. {
  365. int retval = 0;
  366. /* Always disable if version not matched...cannot enable manually. */
  367. if ((mrdump_plat != NULL) && (0 == memcmp(mrdump_cblock.sig, MRDUMP_GO_DUMP, 8))) {
  368. retval = param_set_bool(val, kp);
  369. if (retval == 0) {
  370. mrdump_plat->hw_enable(mrdump_enable);
  371. mrdump_cblock.machdesc.nr_cpus = mrdump_enable ? NR_CPUS : 0;
  372. __inner_flush_dcache_all();
  373. }
  374. }
  375. return retval;
  376. }
  377. static int param_set_mrdump_fstype(const char *val, const struct kernel_param *kp)
  378. {
  379. char strval[16], *strp;
  380. int eval;
  381. strlcpy(strval, val, sizeof(strval));
  382. strp = strstrip(strval);
  383. if (strcmp(strp, "null") == 0)
  384. eval = MRDUMP_FS_NULL;
  385. else if (strcmp(strp, "vfat") == 0)
  386. eval = MRDUMP_FS_VFAT;
  387. else if (strcmp(strp, "ext4") == 0)
  388. eval = MRDUMP_FS_EXT4;
  389. else
  390. eval = MRDUMP_FS_NULL;
  391. *(int *)kp->arg = eval;
  392. mrdump_cblock.machdesc.output_fstype = eval;
  393. __inner_flush_dcache_all();
  394. return 0;
  395. }
  396. static int param_get_mrdump_fstype(char *buffer, const struct kernel_param *kp)
  397. {
  398. char *dev;
  399. switch (mrdump_cblock.machdesc.output_fstype) {
  400. case MRDUMP_FS_NULL:
  401. dev = "null";
  402. break;
  403. case MRDUMP_FS_VFAT:
  404. dev = "vfat";
  405. break;
  406. case MRDUMP_FS_EXT4:
  407. dev = "ext4";
  408. break;
  409. default:
  410. dev = "none(unknown)";
  411. break;
  412. }
  413. strcpy(buffer, dev);
  414. return strlen(dev);
  415. }
  416. static int param_set_mrdump_lbaooo(const char *val, const struct kernel_param *kp)
  417. {
  418. int retval = param_set_ulong(val, kp);
  419. if ((retval == 0) && (mrdump_cblock.machdesc.output_fstype == MRDUMP_FS_EXT4)) {
  420. mrdump_cblock.machdesc.output_lbaooo = mrdump_output_lbaooo;
  421. __inner_flush_dcache_all();
  422. }
  423. return retval;
  424. }
  425. module_param_string(lk, mrdump_lk, sizeof(mrdump_lk), S_IRUGO);
  426. /* sys/modules/mrdump/parameter/lbaooo */
  427. struct kernel_param_ops param_ops_mrdump_lbaooo = {
  428. .set = param_set_mrdump_lbaooo,
  429. .get = param_get_ulong,
  430. };
  431. param_check_ulong(lbaooo, &mrdump_output_lbaooo);
  432. module_param_cb(lbaooo, &param_ops_mrdump_lbaooo, &mrdump_output_lbaooo, S_IRUGO | S_IWUSR);
  433. __MODULE_PARM_TYPE(lbaooo, unsigned long);
  434. /* sys/modules/mrdump/parameter/fstype */
  435. struct kernel_param_ops param_ops_mrdump_fstype = {
  436. .set = param_set_mrdump_fstype,
  437. .get = param_get_mrdump_fstype,
  438. };
  439. param_check_int(fstype, &mrdump_output_fstype);
  440. module_param_cb(fstype, &param_ops_mrdump_fstype, &mrdump_output_fstype, S_IRUGO | S_IWUSR);
  441. __MODULE_PARM_TYPE(fstype, int);
  442. /* sys/modules/mrdump/parameter/enable */
  443. struct kernel_param_ops param_ops_mrdump_enable = {
  444. .set = param_set_mrdump_enable,
  445. .get = param_get_bool,
  446. };
  447. param_check_bool(enable, &mrdump_enable);
  448. module_param_cb(enable, &param_ops_mrdump_enable, &mrdump_enable, S_IRUGO | S_IWUSR);
  449. __MODULE_PARM_TYPE(enable, bool);
  450. /* sys/modules/mrdump/parameter/device */
  451. struct kernel_param_ops param_ops_mrdump_device = {
  452. .set = param_set_mrdump_device,
  453. .get = param_get_mrdump_device,
  454. };
  455. param_check_int(device, &mrdump_output_device);
  456. module_param_cb(device, &param_ops_mrdump_device, &mrdump_output_device, S_IRUGO | S_IWUSR);
  457. __MODULE_PARM_TYPE(device, int);
  458. MODULE_LICENSE("GPL");
  459. MODULE_DESCRIPTION("MediaTek MRDUMP module");
  460. MODULE_AUTHOR("MediaTek Inc.");