2 #include <linux/proc_fs.h>
3 #include <linux/seq_file.h>
4 #include <linux/delay.h>
5 #include <linux/kthread.h>
6 #include <linux/kallsyms.h>
7 #include <linux/notifier.h>
8 #include <linux/kprobes.h>
9 #include <linux/cpumask.h>
10 #include <linux/slab.h>
11 #include <linux/kdebug.h>
12 #include <asm/uaccess.h>
13 #if defined(CONFIG_ARM_PSCI) || (CONFIG_ARM64)
14 #include <mach/mt_secure_api.h>
24 static struct task_struct
*wk_tsk
[NR_CPUS
];
25 extern struct atomic_notifier_head panic_notifier_list
;
29 #define BUG() *((unsigned *)0xaed) = 0xDEAD
32 static int force_panic_hang(struct notifier_block
*this, unsigned long event
, void *ptr
)
34 LOGW("\n ==> force panic flow hang\n");
36 LOGW("\n You should not see this\n");
40 static struct notifier_block panic_test
= {
41 .notifier_call
= force_panic_hang
,
45 void notrace
wdt_atf_hang(void)
47 int cpu
= get_HW_cpuid();
48 LOGE(" CPU %d : wdt_atf_hang\n", cpu
);
55 static int kwdt_thread_test(void *arg
)
57 struct sched_param param
= {.sched_priority
= RTPM_PRIO_WDT
};
58 int cpu
= get_HW_cpuid();
60 sched_setscheduler(current
, SCHED_FIFO
, ¶m
);
61 set_current_state(TASK_INTERRUPTIBLE
);
62 LOGW("\n ==> kwdt_thread_test on CPU %d, test_case = %d\n", cpu
, test_case
);
66 if (cpu
== test_cpu
) {
67 LOGW("\n CPU %d : disable preemption and local IRQ forever", cpu
);
71 LOGW("\n Error : You should not see this !\n");
73 LOGW("\n CPU %d : Do nothing and exit\n ", cpu
);
75 } else if (test_case
== 2) {
76 if (cpu
== test_cpu
) {
78 LOGW("\n CPU %d : disable preemption and local IRQ forever", cpu
);
82 LOGE("\n Error : You should not see this !\n");
84 LOGW("\n CPU %d : disable irq\n ", cpu
);
87 LOGE("\n Error : You should not see this !\n");
89 } else if (test_case
== 3) {
90 if (cpu
== test_cpu
) {
91 LOGW("\n CPU %d : register panic notifier and force hang \n",
93 atomic_notifier_chain_register(&panic_notifier_list
, &panic_test
);
97 LOGE("\n Error : You should not see this !\n");
99 LOGW("\n CPU %d : Do nothing and exit\n ", cpu
);
101 } else if (test_case
== 4) {
102 LOGW("\n CPU %d : disable preemption and local IRQ forever\n ", cpu
);
106 LOGW("\n Error : You should not see this !\n");
107 } else if (test_case
== 5) {
108 LOGW("\n CPU %d : disable preemption and local IRQ/FIQ forever\n ", cpu
);
113 LOGW("\n Error : You should not see this !\n");
114 } else if (test_case
== 6) {
115 LOGW("\n CPU %d : disable preemption and local IRQ/FIQ forever\n ", cpu
);
120 LOGW("\n Error : You should not see this !\n");
125 static ssize_t
proc_generate_wdt_write(struct file
*file
,
126 const char __user
*buf
, size_t size
, loff_t
*ppos
)
130 unsigned char name
[20] = { 0 };
132 if ((size
< 2) || (size
> sizeof(msg
))) {
133 LOGW("\n size = %zx\n", size
);
136 if (copy_from_user(msg
, buf
, size
)) {
137 LOGW("copy_from_user error");
140 test_case
= (unsigned int)msg
[0] - '0';
141 test_cpu
= (unsigned int)msg
[2] - '0';
142 LOGW("test_case = %d, test_cpu = %d", test_case
, test_cpu
);
143 if ((msg
[1] != ':') || (test_case
< 1) || (test_case
> 6)
144 || (test_cpu
< 0) || (test_cpu
> nr_cpu_ids
)) {
145 LOGW("WDT test - Usage: [test case number(1~6):test cpu(0~%d)]\n", nr_cpu_ids
);
149 if (test_case
== 1) {
150 LOGW("Test 1 : One CPU WDT timeout (smp_send_stop succeed)\n");
151 } else if (test_case
== 2) {
152 LOGW("Test 2 : One CPU WDT timeout, other CPU disable irq (smp_send_stop fail in old design)\n");
153 } else if (test_case
== 3) {
154 LOGW("Test 3 : WDT timeout and loop in panic flow\n");
155 } else if (test_case
== 4) {
156 LOGW("Test 4 : All CPU WDT timeout (other CPU stop in the loop)\n");
157 } else if (test_case
== 5) {
158 LOGW("Test 5 : Disable ALL CPU IRQ/FIQ (FIQ : HW_reboot, ATF : HWT \n");
159 } else if (test_case
== 6) {
160 LOGW("Test 6 : (For ATF) HW_REBOOT : change SMC call back function and while loop \n");
162 mt_secure_call(MTK_SIP_KERNEL_WDT
, (u64
)&wdt_atf_hang
, 0, 0);
164 #ifdef CONFIG_ARM_PSCI
165 mt_secure_call(MTK_SIP_KERNEL_WDT
, (u32
)&wdt_atf_hang
, 0, 0);
168 LOGE("\n Unknown test_case %d\n", test_case
);
172 /* create kernel threads and bind on every cpu */
173 for (i
= 0; i
< nr_cpu_ids
; i
++) {
174 sprintf(name
, "wd-test-%d", i
);
175 LOGW("[WDK]thread name: %s\n", name
);
176 wk_tsk
[i
] = kthread_create(kwdt_thread_test
, NULL
, name
);
177 if (IS_ERR(wk_tsk
[i
])) {
178 int ret
= PTR_ERR(wk_tsk
[i
]);
182 kthread_bind(wk_tsk
[i
], i
);
185 for (i
= 0; i
< nr_cpu_ids
; i
++) {
186 LOGW(" wake_up_process(wk_tsk[%d])\n", i
);
187 wake_up_process(wk_tsk
[i
]);
193 static ssize_t
proc_generate_wdt_read(struct file
*file
,
194 char __user
*buf
, size_t size
, loff_t
*ppos
)
196 char buffer
[BUFSIZE
];
197 return sprintf(buffer
, "WDT test - Usage: [test case number:test cpu]\n");
201 /*****************************BEGIN OOPS***************************/
202 /**********BEGIN ISR trigger HWT**********/
203 /* kprobe pre_handler: called just before the probed instruction is executed */
204 static int handler_pre(struct kprobe
*p
, struct pt_regs
*regs
)
206 LOGI("process_name:[%s], pid = %d.\n", current
->comm
, current
->pid
);
211 /* kprobe post_handler: called after the probed instruction is executed */
213 void handler_post(struct kprobe
*p
, struct pt_regs
*regs
, unsigned long flags
)
221 static int handler_fault(struct kprobe
*p
, struct pt_regs
*regs
, int trapnr
);
223 static struct kprobe kp_kpd_irq_handler
= {
224 .symbol_name
= "kpd_irq_handler",
225 .pre_handler
= handler_pre
,
226 .post_handler
= handler_post
,
227 .fault_handler
= handler_fault
,
231 * fault_handler: this is called if an exception is generated for any
232 * instruction within the pre- or post-handler, or when Kprobes
233 * single-steps the probed instruction.
235 static int handler_fault(struct kprobe
*p
, struct pt_regs
*regs
, int trapnr
)
237 LOGE("fault_handler: p->addr = 0x%p, trap #%dn", p
->addr
, trapnr
);
238 unregister_kprobe(&kp_kpd_irq_handler
);
239 LOGI("kprobe at %p unregistered\n", kp_kpd_irq_handler
.addr
);
241 /* Return 0 because we don't handle the fault. */
245 static int register_kprobe_kpd_irq_handler(void)
249 /* All set to register with Kprobes */
250 ret
= register_kprobe(&kp_kpd_irq_handler
);
252 LOGI("register_kprobe failed, returned %d\n", ret
);
254 LOGI("Planted kprobe at %p, press Vol+/- to trigger.\n", kp_kpd_irq_handler
.addr
);
259 /**********END ISR trigger HWT**********/
260 /**********BEGIN panic case**********/
261 static int noinline
stack_overflow_routine(int x
, int y
, int z
)
266 for (i
= 0; i
< (x
+ y
+ z
) * 2; i
++) {
273 static void noinline
buffer_over_flow(void)
276 LOGI("test case : buffer overflow\n");
277 n
= stack_overflow_routine(10, 1, 22);
278 LOGI("%s: %d\n", __func__
, n
);
281 static void noinline
access_null_pointer(void)
283 LOGI("test case : derefence Null pointer\n");
284 *((unsigned *)0) = 0xDEAD;
287 static void noinline
double_free(void)
289 char *p
= kmalloc(32, GFP_KERNEL
);
291 LOGI("test case : double free\n");
292 for (i
= 0; i
< 32; i
++) {
295 LOGI("aee_ut_ke: call free\n");
297 LOGI("aee_ut_ke: call free again\n");
301 static void noinline
devide_by_0(void)
305 LOGI("test case: division by %d\n", ZERO
);
307 LOGI("%s: %d\n", __func__
, number
);
310 /**********END panic case**********/
312 static ssize_t
proc_generate_oops_read(struct file
*file
,
313 char __user
*buf
, size_t size
, loff_t
*ppos
)
316 char buffer
[BUFSIZE
];
317 len
= snprintf(buffer
, BUFSIZE
, "Oops Generated!\n");
318 if (copy_to_user(buf
, buffer
, len
)) {
319 LOGE("%s fail to output info.\n", __func__
);
326 static ssize_t
proc_generate_oops_write(struct file
*file
,
327 const char __user
*buf
, size_t size
, loff_t
*ppos
)
330 int test_case
, test_subcase
, test_cpu
;
332 if ((size
< 2) || (size
> sizeof(msg
))) {
333 LOGW("%s: count = %zx\n", __func__
, size
);
336 if (copy_from_user(msg
, buf
, size
)) {
337 LOGW("%s: error\n", __func__
);
340 test_case
= (unsigned int)msg
[0] - '0';
341 test_subcase
= (unsigned int)msg
[2] - '0';
342 test_cpu
= (unsigned int)msg
[4] - '0';
343 LOGW("test_case = %d-%d, test_cpu = %d\n", test_case
, test_subcase
, test_cpu
);
346 switch (test_subcase
) {
351 access_null_pointer();
364 register_kprobe_kpd_irq_handler();
375 static int nested_panic(struct notifier_block
*this, unsigned long event
, void *ptr
)
377 LOGE("\n => force nested panic\n");
382 static struct notifier_block panic_blk
= {
383 .notifier_call
= nested_panic
,
384 .priority
= INT_MAX
- 100,
387 static ssize_t
proc_generate_nested_ke_read(struct file
*file
,
388 char __user
*buf
, size_t size
, loff_t
*ppos
)
391 atomic_notifier_chain_register(&panic_notifier_list
, &panic_blk
);
392 LOGE("\n => panic_notifier_list registered\n");
394 /* len = sprintf(page, "Nested panic generated\n"); */
399 static ssize_t
proc_generate_nested_ke_write(struct file
*file
,
400 const char __user
*buf
, size_t size
, loff_t
*ppos
)
403 int test_case
, test_subcase
, test_cpu
;
405 if ((size
< 2) || (size
> sizeof(msg
))) {
406 LOGW("%s: count = %zx\n", __func__
, size
);
409 if (copy_from_user(msg
, buf
, size
)) {
410 LOGW("%s: error\n", __func__
);
413 test_case
= (unsigned int)msg
[0] - '0';
414 test_subcase
= (unsigned int)msg
[2] - '0';
415 test_cpu
= (unsigned int)msg
[4] - '0';
416 LOGW("test_case = %d-%d, test_cpu = %d\n", test_case
, test_subcase
, test_cpu
);
419 register_die_notifier(&panic_blk
);
427 static ssize_t
proc_generate_ee_read(struct file
*file
,
428 char __user
*buf
, size_t size
, loff_t
*ppos
)
430 #define TEST_EE_LOG_SIZE 2048
431 #define TEST_EE_PHY_SIZE 65536
433 char buffer
[BUFSIZE
];
439 ptr
= kmalloc(TEST_EE_PHY_SIZE
, GFP_KERNEL
);
440 log
= kmalloc(TEST_EE_LOG_SIZE
, GFP_KERNEL
);
442 LOGE("proc_generate_ee_read kmalloc fail\n");
443 return sprintf(buffer
, "kmalloc fail\n");
445 for (i
= 0; i
< TEST_EE_PHY_SIZE
; i
++) {
446 ptr
[i
] = (i
% 26) + 'A';
448 for (i
= 0; i
< TEST_EE_LOG_SIZE
; i
++) {
451 aed_md_exception_api((int *)log
, TEST_EE_LOG_SIZE
, (int *)ptr
, TEST_EE_PHY_SIZE
, __FILE__
, DB_OPT_FTRACE
);
455 return sprintf(buffer
, "Modem EE Generated\n");
458 static ssize_t
proc_generate_ee_write(struct file
*file
,
459 const char __user
*buf
, size_t size
, loff_t
*ppos
)
464 static ssize_t
proc_generate_combo_read(struct file
*file
,
465 char __user
*buf
, size_t size
, loff_t
*ppos
)
467 #define TEST_COMBO_PHY_SIZE 65536
468 char buffer
[BUFSIZE
];
473 ptr
= kmalloc(TEST_COMBO_PHY_SIZE
, GFP_KERNEL
);
475 LOGE("proc_generate_combo_read kmalloc fail\n");
476 return sprintf(buffer
, "kmalloc fail\n");
478 for (i
= 0; i
< TEST_COMBO_PHY_SIZE
; i
++) {
479 ptr
[i
] = (i
% 26) + 'A';
482 aee_kernel_dal_show("Oops, MT662X is generating core dump, please wait up to 5 min\n");
483 aed_combo_exception(NULL
, 0, (int *)ptr
, TEST_COMBO_PHY_SIZE
, __FILE__
);
486 return sprintf(buffer
, "Combo EE Generated\n");
489 static ssize_t
proc_generate_combo_write(struct file
*file
,
490 const char __user
*buf
, size_t size
, loff_t
*ppos
)
495 static ssize_t
proc_generate_md32_read(struct file
*file
,
496 char __user
*buf
, size_t size
, loff_t
*ppos
)
498 #define TEST_MD32_PHY_SIZE 65536
499 char buffer
[BUFSIZE
];
504 ptr
= kmalloc(TEST_MD32_PHY_SIZE
, GFP_KERNEL
);
506 LOGE("proc_generate_md32_read kmalloc fail\n");
507 return sprintf(buffer
, "kmalloc fail\n");
509 for (i
= 0; i
< TEST_MD32_PHY_SIZE
; i
++) {
510 ptr
[i
] = (i
% 26) + 'a';
513 sprintf(buffer
, "MD32 EE log here\n");
514 aed_md32_exception((int *)buffer
, (int)sizeof(buffer
), (int *)ptr
, TEST_MD32_PHY_SIZE
, __FILE__
);
517 return sprintf(buffer
, "MD32 EE Generated\n");
520 static ssize_t
proc_generate_md32_write(struct file
*file
,
521 const char __user
*buf
, size_t size
, loff_t
*ppos
)
526 static ssize_t
proc_generate_kernel_notify_read(struct file
*file
,
527 char __user
*buf
, size_t size
, loff_t
*ppos
)
529 char buffer
[BUFSIZE
];
531 snprintf(buffer
, BUFSIZE
,
532 "Usage: write message with format \"R|W|E:Tag:You Message\" into this file to generate kernel warning\n");
535 if (copy_to_user(buf
, buffer
, len
)) {
536 LOGE("%s fail to output info.\n", __func__
);
544 static ssize_t
proc_generate_kernel_notify_write(struct file
*file
,
545 const char __user
*buf
, size_t size
, loff_t
*ppos
)
547 char msg
[164], *colon_ptr
;
553 if ((size
< 5) || (size
>= sizeof(msg
))) {
554 LOGW("aed: %s size sould be >= 5 and <= %zx bytes.\n", __func__
, sizeof(msg
));
558 if (copy_from_user(msg
, buf
, size
)) {
559 LOGW("aed: %s unable to read message\n", __func__
);
568 colon_ptr
= strchr(&msg
[2], ':');
569 if ((colon_ptr
== NULL
) || ((colon_ptr
- msg
) > 32)) {
570 LOGW("aed: %s cannot find valid module name\n", __func__
);
577 aee_kernel_reminding(&msg
[2], colon_ptr
+ 1);
581 aee_kernel_warning(&msg
[2], colon_ptr
+ 1);
585 aee_kernel_exception(&msg
[2], colon_ptr
+ 1);
595 static ssize_t
proc_generate_dal_read(struct file
*file
,
596 char __user
*buf
, size_t size
, loff_t
*ppos
)
598 char buffer
[BUFSIZE
];
602 aee_kernel_dal_show("Test for DAL\n");
603 len
= sprintf(buffer
, "DAL Generated\n");
608 static ssize_t
proc_generate_dal_write(struct file
*file
,
609 const char __user
*buf
, size_t size
, loff_t
*ppos
)
614 AED_FILE_OPS(generate_oops
);
615 AED_FILE_OPS(generate_nested_ke
);
616 AED_FILE_OPS(generate_kernel_notify
);
617 AED_FILE_OPS(generate_wdt
);
618 AED_FILE_OPS(generate_ee
);
619 AED_FILE_OPS(generate_combo
);
620 AED_FILE_OPS(generate_md32
);
621 AED_FILE_OPS(generate_dal
);
623 int aed_proc_debug_init(struct proc_dir_entry
*aed_proc_dir
)
625 AED_PROC_ENTRY(generate
-oops
, generate_oops
, S_IRUSR
| S_IWUSR
);
626 AED_PROC_ENTRY(generate
-nested
-ke
, generate_nested_ke
, S_IRUSR
);
627 AED_PROC_ENTRY(generate
-kernel
-notify
, generate_kernel_notify
, S_IRUSR
| S_IWUSR
);
628 AED_PROC_ENTRY(generate
-wdt
, generate_wdt
, S_IRUSR
| S_IWUSR
);
629 AED_PROC_ENTRY(generate
-ee
, generate_ee
, S_IRUSR
);
630 AED_PROC_ENTRY(generate
-combo
, generate_combo
, S_IRUSR
);
631 AED_PROC_ENTRY(generate
-md32
, generate_md32
, S_IRUSR
);
632 AED_PROC_ENTRY(generate
-dal
, generate_dal
, S_IRUSR
);
637 int aed_proc_debug_done(struct proc_dir_entry
*aed_proc_dir
)
639 remove_proc_entry("generate-oops", aed_proc_dir
);
640 remove_proc_entry("generate-nested-ke", aed_proc_dir
);
641 remove_proc_entry("generate-kernel-notify", aed_proc_dir
);
642 remove_proc_entry("generate-ee", aed_proc_dir
);
643 remove_proc_entry("generate-combo", aed_proc_dir
);
644 remove_proc_entry("generate-md32", aed_proc_dir
);
645 remove_proc_entry("generate-wdt", aed_proc_dir
);
646 remove_proc_entry("generate-dal", aed_proc_dir
);
652 int aed_proc_debug_init(struct proc_dir_entry
*aed_proc_dir
)
657 int aed_proc_debug_done(struct proc_dir_entry
*aed_proc_dir
)