blob: b2e03c2406393ed90472da382fcd5401ec805e94 [file] [log] [blame]
rjw1f884582022-01-06 17:20:42 +08001/*
2 * Copyright (c) 2018 MediaTek Inc.
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24#include <arch/ops.h>
25#include <boot_args.h>
26#include <env.h>
27#include <lib/bio.h>
28#include <lib/cksum.h>
29#include <lib/kcmdline.h>
30#include <lib/mempool.h>
31#include <lib/zlib.h>
32#include <libfdt.h>
33#include <malloc.h>
34#include <mrdump.h>
35#include <platform.h>
36#include <platform/mtk_wdt.h>
37#include <printf.h>
38#include <stdarg.h>
39#include <stdint.h>
40#include <stdlib.h>
41#include <string.h>
42#ifdef MTK_PMIC_FULL_RESET
43#include <platform/pmic.h>
44#endif
45
46#include "aee.h"
47#include "kdump.h"
48#include "ram_console.h"
49
50#if WITH_KERNEL_VM
51#include <kernel/vm.h>
52#else
53#include <kernel/novm.h>
54#endif
55
56#ifdef MTK_3LEVEL_PAGETABLE
57#include <target.h>
58#endif
59
60#define MRDUMP_DELAY_TIME 10
61
62extern BOOT_ARGUMENT *g_boot_arg;
63
64static struct mrdump_control_block *mrdump_cblock = NULL;
65static struct mrdump_cblock_result cblock_result;
66static unsigned int log_size;
67static int output_device;
68
69void voprintf(char type, const char *msg, va_list ap)
70{
71 char msgbuf[128], *p;
72
73 p = msgbuf;
74 if (msg[0] == '\r') {
75 *p++ = msg[0];
76 msg++;
77 }
78
79 *p++ = type;
80 *p++ = ':';
81 vsnprintf(p, sizeof(msgbuf) - (p - msgbuf), msg, ap);
82 switch (type) {
83 case 'I':
84 case 'W':
85 case 'E':
86 //video_printf("%s", msgbuf);
87 break;
88 }
89
90 dprintf(CRITICAL,"[%s] %s", MRDUMP_GO_DUMP, msgbuf);
91
92 /* Write log buffer */
93 p = msgbuf;
94 while ((*p != 0) && (log_size < sizeof(cblock_result.log_buf))) {
95 cblock_result.log_buf[log_size] = *p++;
96 log_size++;
97 }
98}
99
100void voprintf_verbose(const char *msg, ...)
101{
102 va_list ap;
103 va_start(ap, msg);
104 voprintf('V', msg, ap);
105 va_end(ap);
106}
107
108void voprintf_debug(const char *msg, ...)
109{
110 va_list ap;
111 va_start(ap, msg);
112 voprintf('D', msg, ap);
113 va_end(ap);
114}
115
116void voprintf_info(const char *msg, ...)
117{
118 va_list ap;
119 va_start(ap, msg);
120 voprintf('I', msg, ap);
121 va_end(ap);
122}
123
124void voprintf_warning(const char *msg, ...)
125{
126 va_list ap;
127 va_start(ap, msg);
128 voprintf('W', msg, ap);
129 va_end(ap);
130}
131
132void voprintf_error(const char *msg, ...)
133{
134 va_list ap;
135 va_start(ap, msg);
136 voprintf('E', msg, ap);
137 va_end(ap);
138}
139
140void vo_show_progress(int sizeM)
141{
142#if 0
143 video_set_cursor((video_get_rows() / 4) * 3, (video_get_colums() - 22)/ 2);
144 video_printf("=====================\n");
145 video_set_cursor((video_get_rows() / 4) * 3 + 1, (video_get_colums() - 22)/ 2);
146 video_printf(">>> Written %4dM <<<\n", sizeM);
147 video_set_cursor((video_get_rows() / 4) * 3 + 2, (video_get_colums() - 22)/ 2);
148 video_printf("=====================\n");
149 video_set_cursor(video_get_rows() - 1, 0);
150
151 dprintf(CRITICAL,"... Written %dM\n", sizeM);
152#endif
153}
154
155static void mrdump_status(const char *status, const char *fmt, va_list ap)
156{
157 char *dest = cblock_result.status;
158 dest += strlcpy(dest, status, sizeof(cblock_result.status));
159 *dest++ = '\n';
160
161 vsnprintf(dest, sizeof(cblock_result.status) - (dest - cblock_result.status), fmt, ap);
162}
163
164void mrdump_status_ok(const char *fmt, ...)
165{
166 va_list ap;
167 va_start(ap, fmt);
168 mrdump_status("OK", fmt, ap);
169 va_end(ap);
170}
171
172void mrdump_status_none(const char *fmt, ...)
173{
174 va_list ap;
175 va_start(ap, fmt);
176 mrdump_status("NONE", fmt, ap);
177 va_end(ap);
178}
179
180void mrdump_status_error(const char *fmt, ...)
181{
182 va_list ap;
183 va_start(ap, fmt);
184 mrdump_status("FAILED", fmt, ap);
185 va_end(ap);
186}
187
188uint32_t g_aee_mode = AEE_MODE_MTK_ENG;
189
190const char *mrdump_mode2string(uint8_t mode)
191{
192 switch (mode) {
193 case AEE_REBOOT_MODE_NORMAL:
194 return "NORMAL-BOOT";
195
196 case AEE_REBOOT_MODE_KERNEL_OOPS:
197 return "KERNEL-OOPS";
198
199 case AEE_REBOOT_MODE_KERNEL_PANIC:
200 return "KERNEL-PANIC";
201
202 case AEE_REBOOT_MODE_NESTED_EXCEPTION:
203 return "NESTED-CPU-EXCEPTION";
204
205 case AEE_REBOOT_MODE_WDT:
206 return "HWT";
207
208 case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
209 return "MANUALDUMP";
210
211 case AEE_REBOOT_MODE_MRDUMP_KEY:
212 return "MRDUMP_KEY";
213
214 case AEE_REBOOT_MODE_HANG_DETECT:
215 return "KERNEL-HANG-DETECT";
216
217 default:
218 return "UNKNOWN-BOOT";
219 }
220}
221
222#define MRDUMP_EXPDB_OFFSET 3145728
223
224static void mrdump_write_result(void)
225{
226 bdev_t *bdev;
227
228 bdev = bio_open_by_label("expdb");
229 if (!bdev) {
230 dprintf(CRITICAL, "%s: no %s partition\n", __func__, "expdb");
231 return;
232 }
233
234 if (bdev->total_size < MRDUMP_EXPDB_OFFSET) {
235 dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%x)\n", __func__,
236 bdev->total_size, MRDUMP_EXPDB_OFFSET);
237 return;
238 }
239 u64 part_offset = bdev->total_size - MRDUMP_EXPDB_OFFSET;
240
241 dprintf(CRITICAL, "%s: offset %lld size %lld\n", __func__, part_offset, bdev->total_size);
242
243 bio_write(bdev, (uchar *)&cblock_result, part_offset, sizeof(cblock_result));
244}
245
246#define SIZE_1MB 1048576ULL
247#define SIZE_64MB 67108864ULL
248
249static uint64_t mrdump_mem_size(void)
250{
251 return physical_memory_size();
252}
253
254static int mrdump_output_device(void)
255{
256 //now only support ext4
257 return MRDUMP_DEV_ISTORAGE_EXT4;
258}
259
260static struct kzip_addlist *mrdump_memlist_fill(void)
261{
262 struct kzip_addlist *memlist =
263 mempool_alloc(sizeof(struct kzip_addlist) * 4, MEMPOOL_ANY);
264 if (memlist == NULL) {
265 return NULL;
266 }
267 void *bufp = mempool_alloc(KDUMP_CORE_HEADER_SIZE, MEMPOOL_ANY);
268 memset(bufp, 0, KDUMP_CORE_HEADER_SIZE);
269
270 dprintf(CRITICAL, "%s address:%p\n", __func__, bufp);
271
272 memlist[0].address = (uint64_t)(uintptr_t) bufp;
273 memlist[0].size = KDUMP_CORE_HEADER_SIZE;
274 memlist[0].type = MEM_NO_MAP;
275 memlist[1].address = (uint64_t)PA_TO_VA((paddr_t)mrdump_cb_addr());
276 memlist[1].size = mrdump_cb_size();
277 memlist[1].type = MEM_NO_MAP;
278 memlist[2].address = (uint64_t)PA_TO_VA(DRAM_BASE_PHY);
279 memlist[2].size = mrdump_mem_size();
280 memlist[2].type = MEM_NO_MAP;
281 memlist[3].address = 0;
282 memlist[3].size = 0;
283 memlist[3].type = MEM_NO_MAP;
284 return memlist;
285}
286
287static void mrdump_memlist_free(struct kzip_addlist *memlist)
288{
289 mempool_free((void *)(uintptr_t)memlist[0].address);
290 mempool_free(memlist);
291}
292
293static void kdump_ui(struct mrdump_control_block *mrdump_cblock)
294{
295#if 0
296 video_clean_screen();
297 video_set_cursor(0, 0);
298#endif
299 mrdump_status_error("Unknown error\n");
300 voprintf_info("Kdump triggerd by '%s' (address:%x, size:%lluM)\n",
301 mrdump_mode2string(mrdump_cblock->crash_record.reboot_mode),
302 DRAM_BASE_PHY, mrdump_mem_size() / 0x100000UL);
303
304 /* check machdesc crc */
305 uint32_t mcrc = crc32(0xffffffff, (const unsigned char *)&mrdump_cblock->machdesc,
306 sizeof(struct mrdump_machdesc)) ^ 0xffffffff;
307 if (mcrc != mrdump_cblock->machdesc_crc) {
308 voprintf_error("Control block machdesc field CRC error (%08x, %08x).\n",
309 mcrc, mrdump_cblock->machdesc_crc);
310 return;
311 }
312
313 struct kzip_addlist *memlist = mrdump_memlist_fill();
314 if (memlist == NULL) {
315 voprintf_error("Cannot allcate memlist memory.\n");
316 return;
317 }
318 kdump_core_header_init(mrdump_cblock, memlist);
319
320 struct aee_timer elapse_time;
321 aee_timer_init(&elapse_time);
322 aee_timer_start(&elapse_time);
323 int dump_ok = -1;
324 switch (output_device) {
325 case MRDUMP_DEV_NONE:
326 mrdump_status_none("Output to None (disabled)\n");
327 voprintf_info("Output to None (disabled)\n");
328 dump_ok = 0;
329 break;
330 case MRDUMP_DEV_NULL:
331 //dump_ok = kdump_null_output(mrdump_cblock, memlist);
332 break;
333 case MRDUMP_DEV_ISTORAGE_EXT4:
334 dump_ok = mrdump_ext4_output(mrdump_cblock, memlist, mrdump_dev_emmc_ext4());
335 break;
336 case MRDUMP_DEV_ISTORAGE_VFAT:
337 //dump_ok = mrdump_vfat_output(mrdump_cblock, memlist, mrdump_dev_emmc_vfat());
338 break;
339 case MRDUMP_DEV_USB:
340 //dump_ok = kdump_usb_output(mrdump_cblock, memlist);
341 break;
342 default:
343 voprintf_error("Unsupport device id %d\n", output_device);
344 dump_ok = -1;
345 }
346 mrdump_memlist_free(memlist);
347
348 aee_mrdump_flush_cblock(mrdump_cblock);
349 aee_timer_stop(&elapse_time);
350 voprintf_info("Dump finished.(%s, %d sec)\n", dump_ok == 0 ? "ok" : "failed",
351 elapse_time.acc_ms / 1000);
352
353 mtk_wdt_restart();
354#if 0
355 video_clean_screen();
356 video_set_cursor(0, 0);
357#endif
358}
359
360int mrdump_detection(void)
361{
362 if (!ram_console_is_abnormal_boot()) {
363 dprintf(CRITICAL, "MT-RAMDUMP: No exception detected, skipped\n");
364 return 0;
365 }
366
367 mrdump_cblock = aee_mrdump_get_params();
368 if (mrdump_cblock == NULL) {
369 dprintf(CRITICAL, "MT-RAMDUMP control block not found\n");
370 return 0;
371 }
372
373 memset(&cblock_result, 0, sizeof(struct mrdump_cblock_result));
374 log_size = 0;
375 strlcpy(cblock_result.sig, MRDUMP_GO_DUMP, sizeof(cblock_result.sig));
376
377 uint8_t reboot_mode = mrdump_cblock->crash_record.reboot_mode;
378
379 if (!g_boot_arg->ddr_reserve_enable) {
380 voprintf_debug("DDR reserve mode disabled\n");
381 mrdump_status_none("DDR reserve mode disabled\n");
382 goto error;
383 }
384
385 if (!g_boot_arg->ddr_reserve_success) {
386 voprintf_debug("DDR reserve mode failed\n");
387 mrdump_status_none("DDR reserve mode failed\n");
388 goto error;
389 }
390
391 if (mrdump_cblock->enabled != MRDUMP_ENABLE_COOKIE) {
392 voprintf_debug("Runtime disabled %x\n", mrdump_cblock->enabled);
393 mrdump_status_none("Runtime disabled\n");
394 goto error;
395 }
396
397 output_device = mrdump_output_device();
398 voprintf_debug("sram record with mode %d\n", reboot_mode);
399 switch (reboot_mode) {
400 case AEE_REBOOT_MODE_GZ_WDT:
401 case AEE_REBOOT_MODE_WDT: {
402 goto end;
403 }
404 case AEE_REBOOT_MODE_NORMAL: {
405 /* MRDUMP_KEY reboot*/
406 if (ram_console_reboot_by_mrdump_key && ram_console_reboot_by_mrdump_key()) {
407 mrdump_cblock->crash_record.reboot_mode = AEE_REBOOT_MODE_MRDUMP_KEY;
408 goto end;
409 } else
410 return 0;
411 }
412 case AEE_REBOOT_MODE_KERNEL_OOPS:
413 case AEE_REBOOT_MODE_KERNEL_PANIC:
414 case AEE_REBOOT_MODE_NESTED_EXCEPTION:
415 case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
416 case AEE_REBOOT_MODE_MRDUMP_KEY:
417 case AEE_REBOOT_MODE_GZ_KE:
418 case AEE_REBOOT_MODE_HANG_DETECT:
419 goto end;
420 }
421 voprintf_debug("Unsupport exception type\n");
422 mrdump_status_none("Unsupport exception type\n");
423
424error:
425 mrdump_write_result();
426 return 0;
427end:
428 if (output_device == MRDUMP_DEV_USB) {
429 g_boot_arg->boot_mode = 2;
430 //set_env("mrdump_output", "usb");
431 }
432
433 return 1;
434}
435
436void mrdump_reboot(void)
437{
438#ifdef MTK_PMIC_FULL_RESET
439 voprintf_debug("Ready for full pmic reset\n");
440 mrdump_write_result();
441 pmic_cold_reset();
442#else
443 voprintf_debug("Ready for reset\n");
444 mrdump_write_result();
445 mtk_arch_reset(1);
446#endif
447}
448
449int mrdump_run2(void)
450{
451 if (mrdump_cblock != NULL) {
452 kdump_ui(mrdump_cblock);
453#ifndef MTK_TC7_FEATURE
454 if (output_device != MRDUMP_DEV_USB) {
455 mrdump_reboot();
456 }
457#endif
458 mrdump_write_result();
459 return 1;
460 }
461 return 0;
462}
463
464void aee_timer_init(struct aee_timer *t)
465{
466 memset(t, 0, sizeof(struct aee_timer));
467}
468
469void aee_timer_start(struct aee_timer *t)
470{
471 t->start_ms = current_time();
472}
473
474void aee_timer_stop(struct aee_timer *t)
475{
476 t->acc_ms += (current_time() - t->start_ms);
477 t->start_ms = 0;
478}
479
480void kdump_core_header_init(const struct mrdump_control_block *kparams,
481 const struct kzip_addlist *memlist)
482{
483 if (kparams->machdesc.page_offset <= 0xffffffffULL) {
484 voprintf_info("32b kernel detected:offset:0x%llx\n", kparams->machdesc.page_offset);
485 kdump_core32_header_init(kparams, memlist);
486 } else {
487 voprintf_info("64b kernel detected:offset:0x%llx\n", kparams->machdesc.page_offset);
488 kdump_core64_header_init(kparams, memlist);
489 }
490}
491
492#ifdef MTK_3LEVEL_PAGETABLE
493vaddr_t scratch_addr(void)
494{
495 return (vaddr_t)target_get_scratch_address();
496}
497#endif
498
499void mrdump_setup_version(void)
500{
501 kcmdline_append("mrdump.lk=" MRDUMP_GO_DUMP);
502}