aee.c 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568
  1. /* Copyright Statement:
  2. *
  3. * This software/firmware and related documentation ("MediaTek Software") are
  4. * protected under relevant copyright laws. The information contained herein
  5. * is confidential and proprietary to MediaTek Inc. and/or its licensors.
  6. * Without the prior written permission of MediaTek inc. and/or its licensors,
  7. * any reproduction, modification, use or disclosure of MediaTek Software,
  8. * and information contained herein, in whole or in part, shall be strictly prohibited.
  9. */
  10. /* MediaTek Inc. (C) 2016. All rights reserved.
  11. *
  12. * BY OPENING THIS FILE, RECEIVER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
  13. * THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
  14. * RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO RECEIVER ON
  15. * AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
  16. * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
  17. * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
  18. * NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
  19. * SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
  20. * SUPPLIED WITH THE MEDIATEK SOFTWARE, AND RECEIVER AGREES TO LOOK ONLY TO SUCH
  21. * THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. RECEIVER EXPRESSLY ACKNOWLEDGES
  22. * THAT IT IS RECEIVER'S SOLE RESPONSIBILITY TO OBTAIN FROM ANY THIRD PARTY ALL PROPER LICENSES
  23. * CONTAINED IN MEDIATEK SOFTWARE. MEDIATEK SHALL ALSO NOT BE RESPONSIBLE FOR ANY MEDIATEK
  24. * SOFTWARE RELEASES MADE TO RECEIVER'S SPECIFICATION OR TO CONFORM TO A PARTICULAR
  25. * STANDARD OR OPEN FORUM. RECEIVER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND
  26. * CUMULATIVE LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
  27. * AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
  28. * OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY RECEIVER TO
  29. * MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE.
  30. */
  31. #include <malloc.h>
  32. #include <printf.h>
  33. #include <stdarg.h>
  34. #include <stdint.h>
  35. #include <stdlib.h>
  36. #include <string.h>
  37. #include <video.h>
  38. #include <platform/mt_typedefs.h>
  39. #include <dev/mrdump.h>
  40. #ifdef MTK_PARTITION_COMMON
  41. #include <env.h>
  42. #else
  43. #include <platform/env.h>
  44. #endif
  45. #include <platform/mtk_key.h>
  46. #include <platform/mtk_wdt.h>
  47. #include <platform/mt_gpt.h>
  48. #include <target/cust_key.h>
  49. #include <platform/boot_mode.h>
  50. #include <bootimg.h>
  51. #include <platform/ram_console.h>
  52. #include <arch/ops.h>
  53. #include <platform.h>
  54. #include "aee.h"
  55. #include "mrdump_private.h"
  56. #ifdef MTK_3LEVEL_PAGETABLE
  57. #include <target.h>
  58. #endif
  59. #define MRDUMP_DELAY_TIME 10
  60. extern BOOT_ARGUMENT *g_boot_arg;
  61. extern BOOTMODE g_boot_mode;
  62. static struct mrdump_control_block *mrdump_cblock = NULL;
  63. static struct mrdump_cblock_result cblock_result;
  64. static unsigned int log_size;
  65. static int output_device;
  66. void voprintf(char type, const char *msg, va_list ap)
  67. {
  68. char msgbuf[128], *p;
  69. p = msgbuf;
  70. if (msg[0] == '\r') {
  71. *p++ = msg[0];
  72. msg++;
  73. }
  74. *p++ = type;
  75. *p++ = ':';
  76. vsnprintf(p, sizeof(msgbuf) - (p - msgbuf), msg, ap);
  77. switch (type) {
  78. case 'I':
  79. case 'W':
  80. case 'E':
  81. video_printf("%s", msgbuf);
  82. break;
  83. }
  84. dprintf(CRITICAL,"[%s] %s", MRDUMP_GO_DUMP, msgbuf);
  85. /* Write log buffer */
  86. p = msgbuf;
  87. while ((*p != 0) && (log_size < sizeof(cblock_result.log_buf))) {
  88. cblock_result.log_buf[log_size] = *p++;
  89. log_size++;
  90. }
  91. }
  92. void voprintf_verbose(const char *msg, ...)
  93. {
  94. va_list ap;
  95. va_start(ap, msg);
  96. voprintf('V', msg, ap);
  97. va_end(ap);
  98. }
  99. void voprintf_debug(const char *msg, ...)
  100. {
  101. va_list ap;
  102. va_start(ap, msg);
  103. voprintf('D', msg, ap);
  104. va_end(ap);
  105. }
  106. void voprintf_info(const char *msg, ...)
  107. {
  108. va_list ap;
  109. va_start(ap, msg);
  110. voprintf('I', msg, ap);
  111. va_end(ap);
  112. }
  113. void voprintf_warning(const char *msg, ...)
  114. {
  115. va_list ap;
  116. va_start(ap, msg);
  117. voprintf('W', msg, ap);
  118. va_end(ap);
  119. }
  120. void voprintf_error(const char *msg, ...)
  121. {
  122. va_list ap;
  123. va_start(ap, msg);
  124. voprintf('E', msg, ap);
  125. va_end(ap);
  126. }
  127. void vo_show_progress(int sizeM)
  128. {
  129. video_set_cursor((video_get_rows() / 4) * 3, (video_get_colums() - 22)/ 2);
  130. video_printf("=====================\n");
  131. video_set_cursor((video_get_rows() / 4) * 3 + 1, (video_get_colums() - 22)/ 2);
  132. video_printf(">>> Written %4dM <<<\n", sizeM);
  133. video_set_cursor((video_get_rows() / 4) * 3 + 2, (video_get_colums() - 22)/ 2);
  134. video_printf("=====================\n");
  135. video_set_cursor(video_get_rows() - 1, 0);
  136. dprintf(CRITICAL,"... Written %dM\n", sizeM);
  137. }
  138. static void mrdump_status(const char *status, const char *fmt, va_list ap)
  139. {
  140. char *dest = cblock_result.status;
  141. dest += strlcpy(dest, status, sizeof(cblock_result.status));
  142. *dest++ = '\n';
  143. vsnprintf(dest, sizeof(cblock_result.status) - (dest - cblock_result.status), fmt, ap);
  144. }
  145. void mrdump_status_ok(const char *fmt, ...)
  146. {
  147. va_list ap;
  148. va_start(ap, fmt);
  149. mrdump_status("OK", fmt, ap);
  150. va_end(ap);
  151. }
  152. void mrdump_status_none(const char *fmt, ...)
  153. {
  154. va_list ap;
  155. va_start(ap, fmt);
  156. mrdump_status("NONE", fmt, ap);
  157. va_end(ap);
  158. }
  159. void mrdump_status_error(const char *fmt, ...)
  160. {
  161. va_list ap;
  162. va_start(ap, fmt);
  163. mrdump_status("FAILED", fmt, ap);
  164. va_end(ap);
  165. }
  166. const const char *mrdump_mode2string(uint8_t mode)
  167. {
  168. switch (mode) {
  169. case AEE_REBOOT_MODE_NORMAL:
  170. return "NORMAL-BOOT";
  171. case AEE_REBOOT_MODE_KERNEL_OOPS:
  172. return "KERNEL-OOPS";
  173. case AEE_REBOOT_MODE_KERNEL_PANIC:
  174. return "KERNEL-PANIC";
  175. case AEE_REBOOT_MODE_NESTED_EXCEPTION:
  176. return "NESTED-CPU-EXCEPTION";
  177. case AEE_REBOOT_MODE_WDT:
  178. return "HWT";
  179. case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
  180. return "MANUALDUMP";
  181. case AEE_REBOOT_MODE_MRDUMP_KEY:
  182. return "MRDUMP_KEY";
  183. case AEE_REBOOT_MODE_HANG_DETECT:
  184. return "KERNEL-HANG-DETECT";
  185. default:
  186. return "UNKNOWN-BOOT";
  187. }
  188. }
  189. #define MRDUMP_EXPDB_OFFSET 3145728
  190. static void mrdump_write_result(void)
  191. {
  192. struct mrdump_dev *blkpart = mrdump_dev_blkpart("expdb");
  193. if (blkpart != NULL) {
  194. u64 part_size = blkpart->get_size(blkpart);
  195. if (part_size < MRDUMP_EXPDB_OFFSET + sizeof(cblock_result)) {
  196. dprintf(CRITICAL, "%s: partition size(%llx) is less then reserved (%x)\n",
  197. __func__, part_size, MRDUMP_EXPDB_OFFSET);
  198. free(blkpart);
  199. return;
  200. }
  201. blkpart->write(blkpart, part_size - MRDUMP_EXPDB_OFFSET,
  202. (uint8_t *) &cblock_result, sizeof(cblock_result));
  203. free(blkpart);
  204. }
  205. else {
  206. dprintf(CRITICAL, "%s: Cannot find expdb partition\n", __func__);
  207. }
  208. }
  209. #define SIZE_1MB 1048576ULL
  210. #define SIZE_64MB 67108864ULL
  211. static uint64_t mrdump_mem_size(void)
  212. {
  213. uint64_t total_dump_size = physical_memory_size();
  214. const char *mem_size_param = get_env("mrdump_mem_size");
  215. if (mem_size_param != NULL) {
  216. uint64_t mem_size = atoi(mem_size_param) * SIZE_1MB;
  217. voprintf_info("Memory dump size set to %uM\n", (unsigned int) (mem_size / SIZE_1MB));
  218. if (mem_size >= SIZE_64MB) {
  219. /* minimum 64m */
  220. total_dump_size = MIN(total_dump_size, mem_size);
  221. }
  222. }
  223. return total_dump_size;
  224. }
  225. int mrdump_set_output_device(const char *output_dev)
  226. {
  227. int retval = MRDUMP_DEV_UNKNOWN;
  228. if (strcmp(output_dev, "none") == 0) {
  229. retval = MRDUMP_DEV_NONE;
  230. }
  231. else if (strcmp(output_dev, "null") == 0) {
  232. retval = MRDUMP_DEV_NULL;
  233. }
  234. else if (strcmp(output_dev, "usb") == 0) {
  235. retval = MRDUMP_DEV_USB;
  236. }
  237. else if (strcmp(output_dev, "partition") == 0) {
  238. retval = MRDUMP_DEV_PARTITION;
  239. }
  240. else if (strcmp(output_dev, "internal-storage") == 0) {
  241. retval = MRDUMP_DEV_ISTORAGE;
  242. }
  243. if (retval != MRDUMP_DEV_UNKNOWN) {
  244. if (set_env("mrdump_output", output_dev) == 0) {
  245. dprintf(CRITICAL, "%s: defaults: %s\n",__func__, output_dev);
  246. }
  247. else {
  248. dprintf(CRITICAL, "%s: fail to set default mrdump output device\n", __func__);
  249. }
  250. }
  251. else {
  252. dprintf(CRITICAL, "%s: unknown output device %s\n",__func__, output_dev);
  253. }
  254. return retval;
  255. }
  256. int mrdump_get_default_output_device(void)
  257. {
  258. const char *output_device_param = get_env("mrdump_output");
  259. if (output_device_param != NULL) {
  260. if (strcmp(output_device_param, "none") == 0)
  261. return MRDUMP_DEV_NONE;
  262. if (strcmp(output_device_param, "null") == 0)
  263. return MRDUMP_DEV_NULL;
  264. if (strcmp(output_device_param, "internal-storage") == 0)
  265. return MRDUMP_DEV_ISTORAGE;
  266. if (strcmp(output_device_param, "usb") == 0)
  267. return MRDUMP_DEV_USB;
  268. if (strcmp(output_device_param, "partition") == 0)
  269. return MRDUMP_DEV_PARTITION;
  270. dprintf(CRITICAL, "%s: unknown output device %s\n",__func__,
  271. output_device_param);
  272. return MRDUMP_DEV_UNKNOWN;
  273. }
  274. #if defined(MRDUMP_DEFAULT_NONE)
  275. return mrdump_set_output_device("none");
  276. #elif defined(MRDUMP_DEFAULT_NULL)
  277. return mrdump_set_output_device("null");
  278. #elif defined(MRDUMP_DEFAULT_USB_DUMP)
  279. return mrdump_set_output_device("usb");
  280. #elif defined(MRDUMP_DEFAULT_MRDUMP_PARTITION)
  281. return mrdump_set_output_device("partition");
  282. #elif defined(MRDUMP_DEFAULT_DATA_PARTITION)
  283. return mrdump_set_output_device("internal-storage");
  284. #else
  285. #ifdef MRDUMP_PARTITION_ENABLE
  286. return mrdump_set_output_device("partition");
  287. #else
  288. return mrdump_set_output_device("internal-storage");
  289. #endif
  290. #endif
  291. }
  292. static struct kzip_addlist *mrdump_memlist_fill(void)
  293. {
  294. struct kzip_addlist *memlist = malloc(sizeof(struct kzip_addlist) * 4);
  295. if (memlist == NULL) {
  296. return NULL;
  297. }
  298. void *bufp = malloc(MRDUMP_CORE_HEADER_SIZE);
  299. if (bufp == NULL) {
  300. free(memlist);
  301. return NULL;
  302. }
  303. memset(bufp, 0, MRDUMP_CORE_HEADER_SIZE);
  304. memlist[0].address = (uint64_t)(uintptr_t) bufp;
  305. memlist[0].size = MRDUMP_CORE_HEADER_SIZE;
  306. memlist[0].type = MEM_NO_MAP;
  307. memlist[1].address = (uint64_t)(uintptr_t) mrdump_cb_addr();
  308. memlist[1].size = mrdump_cb_size();
  309. memlist[1].type = MEM_NO_MAP;
  310. memlist[2].address = DRAM_PHY_ADDR;
  311. memlist[2].size = mrdump_mem_size();
  312. memlist[2].type = MEM_DO_MAP;
  313. memlist[3].address = 0;
  314. memlist[3].size = 0;
  315. memlist[3].type = MEM_NO_MAP;
  316. return memlist;
  317. }
  318. static void mrdump_memlist_free(struct kzip_addlist *memlist)
  319. {
  320. free((void *)(uintptr_t)memlist[0].address);
  321. free(memlist);
  322. }
  323. static void kdump_ui(struct mrdump_control_block *mrdump_cblock)
  324. {
  325. video_clean_screen();
  326. video_set_cursor(0, 0);
  327. mrdump_status_error("Unknown error\n");
  328. voprintf_info("Kdump triggerd by '%s' (address:%x, size:%lluM)\n",
  329. mrdump_mode2string(mrdump_cblock->crash_record.reboot_mode),
  330. DRAM_PHY_ADDR, mrdump_mem_size() / 0x100000UL);
  331. /* check machdesc crc */
  332. uint32_t mcrc = crc32(0xffffffff, (const unsigned char*)&mrdump_cblock->machdesc,
  333. sizeof(struct mrdump_machdesc)) ^ 0xffffffff;
  334. if (mcrc != mrdump_cblock->machdesc_crc) {
  335. voprintf_error("Control block machdesc field CRC error (%08x, %08x).\n",
  336. mcrc, mrdump_cblock->machdesc_crc);
  337. return;
  338. }
  339. struct kzip_addlist *memlist_cmm = mrdump_memlist_fill_cmm(mrdump_cblock);
  340. struct kzip_addlist *memlist = mrdump_memlist_fill();
  341. if (memlist == NULL) {
  342. voprintf_error("Cannot allcate memlist memory.\n");
  343. return;
  344. }
  345. mrdump_core_header_init(mrdump_cblock, memlist);
  346. struct aee_timer elapse_time;
  347. aee_timer_init(&elapse_time);
  348. aee_timer_start(&elapse_time);
  349. int dump_ok;
  350. switch (output_device) {
  351. case MRDUMP_DEV_NONE:
  352. mrdump_status_none("Output to None (disabled)\n");
  353. voprintf_info("Output to None (disabled)\n");
  354. dump_ok = 0;
  355. break;
  356. case MRDUMP_DEV_NULL:
  357. dump_ok = mrdump_null_output(mrdump_cblock, memlist);
  358. break;
  359. case MRDUMP_DEV_ISTORAGE:
  360. dump_ok = mrdump_ext4_output(mrdump_cblock, memlist, mrdump_dev_blkpart("userdata"));
  361. break;
  362. case MRDUMP_DEV_USB:
  363. dump_ok = mrdump_usb_output(mrdump_cblock, memlist, memlist_cmm);
  364. break;
  365. case MRDUMP_DEV_PARTITION:
  366. dump_ok = mrdump_partition_output(mrdump_cblock, memlist, mrdump_dev_blkpart("mrdump"));
  367. break;
  368. default:
  369. voprintf_error("Unsupport device id %d\n", output_device);
  370. dump_ok = -1;
  371. }
  372. mrdump_memlist_free(memlist);
  373. mrdump_memlist_free_cmm(memlist_cmm);
  374. aee_mrdump_flush_cblock(mrdump_cblock);
  375. aee_timer_stop(&elapse_time);
  376. voprintf_info("Dump finished.(%s, %d sec)\n", dump_ok == 0 ? "ok" : "failed", elapse_time.acc_ms / 1000);
  377. mtk_wdt_restart();
  378. video_clean_screen();
  379. video_set_cursor(0, 0);
  380. }
  381. int mrdump_detection(void)
  382. {
  383. if (mrdump_check_enable() > MRDUMP_ALWAYS_ENABLE)
  384. return 0;
  385. mrdump_key_secure_enable();
  386. output_device = mrdump_get_default_output_device();
  387. if (output_device == MRDUMP_DEV_UNKNOWN) {
  388. return 0;
  389. }
  390. if (!ram_console_is_abnormal_boot()) {
  391. dprintf(CRITICAL, "MT-RAMDUMP: No exception detected, skipped\n");
  392. return 0;
  393. }
  394. mrdump_cblock = aee_mrdump_get_params();
  395. if (mrdump_cblock == NULL) {
  396. dprintf(CRITICAL, "MT-RAMDUMP control block not found\n");
  397. return 0;
  398. }
  399. memset(&cblock_result, 0, sizeof(struct mrdump_cblock_result));
  400. log_size = 0;
  401. strlcpy(cblock_result.sig, MRDUMP_GO_DUMP, sizeof(cblock_result.sig));
  402. uint8_t reboot_mode = mrdump_cblock->crash_record.reboot_mode;
  403. if (!g_boot_arg->ddr_reserve_enable) {
  404. voprintf_debug("DDR reserve mode disabled\n");
  405. mrdump_status_none("DDR reserve mode disabled\n");
  406. goto error;
  407. }
  408. if (!g_boot_arg->ddr_reserve_success) {
  409. voprintf_debug("DDR reserve mode failed\n");
  410. mrdump_status_none("DDR reserve mode failed\n");
  411. goto error;
  412. }
  413. if (mrdump_cblock->enabled != MRDUMP_ENABLE_COOKIE) {
  414. voprintf_debug("Runtime disabled %x\n", mrdump_cblock->enabled);
  415. mrdump_status_none("Runtime disabled\n");
  416. goto error;
  417. }
  418. voprintf_debug("sram record with mode %d\n", reboot_mode);
  419. switch (reboot_mode) {
  420. case AEE_REBOOT_MODE_GZ_WDT:
  421. case AEE_REBOOT_MODE_WDT: {
  422. goto end;
  423. }
  424. case AEE_REBOOT_MODE_NORMAL: {
  425. /* MRDUMP_KEY reboot*/
  426. if (ram_console_reboot_by_mrdump_key && ram_console_reboot_by_mrdump_key()) {
  427. mrdump_cblock->crash_record.reboot_mode = AEE_REBOOT_MODE_MRDUMP_KEY;
  428. mrdump_status_none("set reboot_mode to MRDUMP_KEY\n");
  429. goto end;
  430. } else
  431. return 0;
  432. }
  433. case AEE_REBOOT_MODE_KERNEL_OOPS:
  434. case AEE_REBOOT_MODE_KERNEL_PANIC:
  435. case AEE_REBOOT_MODE_NESTED_EXCEPTION:
  436. case AEE_REBOOT_MODE_EXCEPTION_KDUMP:
  437. case AEE_REBOOT_MODE_MRDUMP_KEY:
  438. case AEE_REBOOT_MODE_GZ_KE:
  439. case AEE_REBOOT_MODE_HANG_DETECT:
  440. goto end;
  441. }
  442. voprintf_debug("Unsupport exception type\n");
  443. mrdump_status_none("Unsupport exception type\n");
  444. error:
  445. mrdump_write_result();
  446. return 0;
  447. end:
  448. if (output_device == MRDUMP_DEV_USB) {
  449. g_boot_mode = FASTBOOT;
  450. if (set_env("mrdump_output", "usb")) {
  451. dprintf(CRITICAL, "%s: default usb dump\n",__func__);
  452. }
  453. else {
  454. dprintf(CRITICAL, "%s: fail to set default usb mrdump\n", __func__);
  455. }
  456. }
  457. return 1;
  458. }
  459. void mrdump_reboot(void)
  460. {
  461. #ifdef MTK_PMIC_FULL_RESET
  462. voprintf_debug("Ready for full pmic reset\n");
  463. mrdump_write_result();
  464. mtk_arch_full_reset();
  465. #else
  466. voprintf_debug("Ready for reset\n");
  467. mrdump_write_result();
  468. mtk_arch_reset(1);
  469. #endif
  470. }
  471. int mrdump_run2(void)
  472. {
  473. if (mrdump_cblock != NULL) {
  474. kdump_ui(mrdump_cblock);
  475. if (output_device != MRDUMP_DEV_USB) {
  476. mrdump_reboot();
  477. }
  478. mrdump_write_result();
  479. return 1;
  480. }
  481. return 0;
  482. }
  483. void aee_timer_init(struct aee_timer *t)
  484. {
  485. memset(t, 0, sizeof(struct aee_timer));
  486. }
  487. void aee_timer_start(struct aee_timer *t)
  488. {
  489. t->start_ms = get_timer_masked();
  490. }
  491. void aee_timer_stop(struct aee_timer *t)
  492. {
  493. t->acc_ms += (get_timer_masked() - t->start_ms);
  494. t->start_ms = 0;
  495. }
  496. #ifdef MTK_3LEVEL_PAGETABLE
  497. vaddr_t scratch_addr(void)
  498. {
  499. return (vaddr_t)target_get_scratch_address();
  500. }
  501. #endif