| /******************************************************************************* |
| * °æÈ¨ËùÓÐ (C)2016, ÖÐÐËͨѶ¹É·ÝÓÐÏÞ¹«Ë¾¡£ |
| * |
| * ÎļþÃû³Æ: ramdump_client_cap.c |
| * Îļþ±êʶ: ramdump_client_cap.c |
| * ÄÚÈÝÕªÒª: ramdump cap¿Í»§¶ËÒì³£ËÀ»úÏÖ³¡Êý¾Ýµ¼³öʵÏÖ |
| * |
| * ÐÞ¸ÄÈÕÆÚ °æ±¾ºÅ Ð޸ıê¼Ç ÐÞ¸ÄÈË ÐÞ¸ÄÄÚÈÝ |
| * ------------------------------------------------------------------------------ |
| * 2019/10/10 V1.0 Create 00130574 ´´½¨ |
| * |
| *******************************************************************************/ |
| |
| /******************************************************************************* |
| * Í·Îļþ * |
| *******************************************************************************/ |
| #include "ramdump.h" |
| #include "ramdump_arch.h" |
| #include <linux/module.h> |
| #include <linux/soc/zte/rpmsg.h> |
| #include "ram_config.h" |
| |
| #ifdef __cplusplus |
| extern "C" { |
| #endif |
| |
| /******************************************************************************* |
| * ³£Á¿¶¨Òå * |
| *******************************************************************************/ |
| |
| /******************************************************************************* |
| * ºê¶¨Òå * |
| *******************************************************************************/ |
| |
| /******************************************************************************* |
| * Êý¾ÝÀàÐͶ¨Òå * |
| *******************************************************************************/ |
| |
| /******************************************************************************* |
| * º¯ÊýÉùÃ÷ * |
| *******************************************************************************/ |
| extern void ramdump_register_callbacks(void); |
| extern unsigned char *ramdump_phy_to_vir(unsigned long phy, unsigned long size); |
| extern void ramdump_shared_mem_init(void); |
| extern void ramdump_data_transfer_to_device(void); |
| extern void ramdump_oss_data_trans_init(void); |
| extern unsigned char *ramdump_export_flag_base; |
| |
| /******************************************************************************* |
| * ¾Ö²¿¾²Ì¬±äÁ¿¶¨Òå * |
| *******************************************************************************/ |
| #define RAMDUMP_ON_DEFAULT_VAL (1) |
| |
| /******************************************************************************* |
| * È«¾Ö±äÁ¿¶¨Òå * |
| *******************************************************************************/ |
| /* |
| * run time control dump or not, use ( echo "0" > ramdump_on ) to close ramdump |
| */ |
| int sysctl_ramdump_on_panic = RAMDUMP_ON_DEFAULT_VAL; |
| int ramdump_cap_init_flag = -1; |
| int ramdump_count = 0; |
| int ramdump_server_exp_core = RAMDUMP_FALSE; |
| #ifdef CONFIG_RAMDUMP_USER |
| unsigned int sysctl_ramdump_on_user = 1; |
| #endif |
| unsigned int ramdump_export_mode = 0xFF; |
| /* Cmm file content */ |
| unsigned char *ramdump_cap_cmm_buf = NULL; |
| /* err log file */ |
| unsigned char *ramdump_cap_error_log = NULL; |
| unsigned int *cap_ddr_len_base = NULL; |
| unsigned int sysctl_ramdump_emmc_size = 0x0; |
| unsigned int sysctl_ramdump_emmc_start_addr = 0xFFFF; |
| |
| static struct ctl_table cfg_ramdump_array[] = { |
| #ifdef CONFIG_RAMDUMP_USER |
| { |
| .procname = "sysctl_ramdump_on_user", |
| .data = &sysctl_ramdump_on_user, |
| .maxlen = sizeof(sysctl_ramdump_on_user), |
| .mode = 0644, |
| .proc_handler = proc_dointvec_minmax, |
| .extra1 = SYSCTL_ZERO, |
| .extra2 = SYSCTL_ONE, |
| }, |
| #endif |
| { |
| .procname = "ramdump_start_addr", |
| .data = &sysctl_ramdump_emmc_start_addr, |
| .maxlen = sizeof(u64), |
| .mode = 0644, |
| .proc_handler = proc_dointvec_minmax, |
| }, |
| { |
| .procname = "ramdump_emmc_size", |
| .data = &sysctl_ramdump_emmc_size, |
| .maxlen = sizeof(u64), |
| .mode = 0644, |
| .proc_handler = proc_doulongvec_minmax, |
| }, |
| |
| { } |
| }; |
| |
| static struct ctl_table sysctl_ramdump_table[] = { |
| { |
| .procname = "ramdump_ap", |
| .mode = 0555, |
| .child = cfg_ramdump_array, |
| }, |
| { } |
| }; |
| |
| /******************************************************************************* |
| * ¾Ö²¿º¯ÊýʵÏÖ * |
| *******************************************************************************/ |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_cap_icp_handle |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) buf: icp msg addr |
| * len: icp msg len |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used for ramdump client icp msg handle, common entry |
| *******************************************************************************/ |
| static void ramdump_cap_icp_handle(void *buf, unsigned int len) |
| { |
| ramdump_msg_t *icp_msg = (ramdump_msg_t *)buf; |
| |
| ramdump_server_exp_core = RAMDUMP_SUCCESS; |
| |
| switch(icp_msg->msg_id) |
| { |
| case RAMDUMP_MSG_EXCEPT: |
| { |
| ramdump_panic("trans server received forced dump request from Ap server!\n"); |
| break; |
| } |
| |
| default: |
| { |
| ramdump_panic("trans server received forced dump request from Ap server!\n"); |
| break; |
| } |
| } |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_oss_icp_create_channel |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) actorID: icp send core id |
| chID: icp channel id |
| size: icp channel size |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: int: if msg send success |
| * ÆäËü˵Ã÷: |
| *******************************************************************************/ |
| static int ramdump_cap_icp_create_channel(T_RpMsg_CoreID dstCoreID, T_RpMsg_ChID chID, unsigned int size) |
| { |
| return rpmsgCreateChannel(dstCoreID, chID, size); |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_oss_icp_regcallback |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) actorID: icp send core id |
| chID: icp channel id |
| callback:icp callback fun |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: int: if msg send success |
| * ÆäËü˵Ã÷: |
| *******************************************************************************/ |
| static int ramdump_cap_icp_regcallback (T_RpMsg_CoreID coreID, unsigned int chID, T_RpMsg_Callback callback) |
| { |
| return rpmsgRegCallBack(coreID, chID, callback); |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_init_sysctl_table |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: ×¢²ásysctlÃüÁÓû§Ì¬Ê¹ÓÃsysctl¿ØÖÆramdump´æ´¢µØÖ· |
| *******************************************************************************/ |
| void ramdump_init_sysctl_table(void) |
| { |
| register_sysctl_table(sysctl_ramdump_table); |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_cap_icp_init |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used for ramdump client icp init |
| *******************************************************************************/ |
| static int ramdump_cap_icp_init(void) |
| { |
| int ret = 0; |
| |
| ret = ramdump_cap_icp_create_channel( |
| RAMDUMP_SERVER_AP, |
| RAMDUMP_CHANNEL, |
| RAMDUMP_CHANNEL_SIZE); |
| |
| if (ret != RAMDUMP_SUCCESS) |
| { |
| return ret; |
| } |
| ret = ramdump_cap_icp_regcallback( |
| RAMDUMP_SERVER_AP, |
| RAMDUMP_CHANNEL, |
| ramdump_cap_icp_handle); |
| |
| if (ret != RAMDUMP_SUCCESS) |
| { |
| return ret; |
| } |
| return RAMDUMP_SUCCESS; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_notify_server_panic |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used for cap notify ramdump server to panic |
| *******************************************************************************/ |
| static int ramdump_notify_server_panic(void) |
| { |
| int ret = 0; |
| T_RpMsg_Msg rpMsg = {0}; |
| ramdump_msg_t ramdumpMsg = {0}; |
| |
| ramdumpMsg.msg_id = RAMDUMP_MSG_EXCEPT; |
| ramdumpMsg.cpu_id = CORE_AP; |
| |
| rpMsg.coreID = RAMDUMP_SERVER_AP; |
| rpMsg.chID = RAMDUMP_CHANNEL; |
| rpMsg.flag = RPMSG_WRITE_INT | RPMSG_WRITE_IRQLOCK; |
| rpMsg.len = sizeof(ramdump_msg_t); |
| rpMsg.buf = &ramdumpMsg; |
| |
| ret = rpmsgWrite(&rpMsg); |
| return ret; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_cap_store_ram_conf |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) mem: addr |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: unsigend char*: changed addr |
| * ÆäËü˵Ã÷: This function is used to store ram conf |
| *******************************************************************************/ |
| static unsigned char *ramdump_cap_store_ram_conf(unsigned char *mem) |
| { |
| mem += sprintf( |
| mem, |
| "data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n", |
| "cap_ddr.bin", |
| (unsigned int)DDR_BASE_CAP_ADDR_PA, |
| (unsigned int)(DDR_BASE_CAP_ADDR_PA + *cap_ddr_len_base - 1)); |
| mem += sprintf( |
| mem, |
| "data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n", |
| "cap.cmm", |
| (unsigned int)RAMDUMP_CAP_CMM_BUF_ADDR, |
| (unsigned int)(RAMDUMP_CAP_CMM_BUF_ADDR + RAMDUMP_CAP_CMM_BUF_LEN_REAL - 1)); |
| mem += sprintf( |
| mem, |
| "data.load.binary &ramdump_dir\\%s A:0x%x--A:0x%x /noclear\n", |
| "cap_err_log.txt", |
| (unsigned int)RAMDUMP_CAP_LOG_BUF_ADDR, |
| (unsigned int)(RAMDUMP_CAP_LOG_BUF_ADDR + RAMDUMP_CAP_LOG_BUF_LEN - 1)); |
| return mem; |
| } |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_cap_cmm_create |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used for server to generate cmm scripts |
| *******************************************************************************/ |
| static void ramdump_cap_cmm_create(void) |
| { |
| unsigned char *pcmm_buf = ramdump_cap_cmm_buf; |
| |
| memset(ramdump_cap_cmm_buf, 0, RAMDUMP_CAP_CMM_BUF_LEN_REAL); |
| |
| // store the cmm BEGIN |
| pcmm_buf += sprintf(pcmm_buf, "ENTRY &ramdump_dir\n"); |
| |
| // store procmodes regs |
| pcmm_buf = ramdump_arch_store_modes_regs(pcmm_buf); |
| |
| // store ram config |
| pcmm_buf = ramdump_cap_store_ram_conf(pcmm_buf); |
| |
| // store memory map control regs |
| pcmm_buf = ramdump_arch_store_mm_regs(pcmm_buf); |
| |
| // store end symbol |
| pcmm_buf += sprintf(pcmm_buf, "ENDDO\n"); |
| |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_trans_cap_error_log_create |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used to create err log file |
| *******************************************************************************/ |
| static void ramdump_cap_error_log_create(void) |
| { |
| unsigned char *buf = ramdump_cap_error_log; |
| |
| memset(ramdump_cap_error_log, 0, RAMDUMP_CAP_LOG_BUF_LEN); |
| buf += sprintf(buf, "dump at core%d,", smp_processor_id()); |
| if (current->mm != NULL) |
| buf += sprintf(buf, "in user,task is: %s\n", current->comm); |
| else |
| buf += sprintf(buf, "in kernel,task is: %s\n", current->comm); |
| |
| if (ramdump_server_exp_core) |
| buf += sprintf(buf, "recv dumpinfo from ap\n"); |
| } |
| |
| /******************************************************************************* |
| * È«¾Öº¯ÊýʵÏÖ * |
| *******************************************************************************/ |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_ram_conf_table_add |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) ram_name: dump ram name |
| ram_start: dump ram start(virtual addr) |
| ram_size: dump ram size |
| ram_virt: dump ram virt addr |
| ram_flag: dump ram flag(copy/exter/callback) |
| ram_extra: dump ram extra access addr |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used to add dump ram conf into public table |
| *******************************************************************************/ |
| void ramdump_ram_conf_table_add( |
| char *ram_name, |
| unsigned long ram_phy, |
| unsigned long ram_size, |
| unsigned long ram_virt, |
| unsigned long ram_flag, |
| unsigned long ram_extra) |
| { |
| } |
| void ramdump_init_cmm_buf(void) |
| { |
| /* Cmm file content */ |
| ramdump_cap_cmm_buf = ramdump_phy_to_vir((unsigned long)RAMDUMP_CAP_CMM_BUF_ADDR, RAMDUMP_CAP_CMM_BUF_LEN_REAL); |
| /* err log file */ |
| ramdump_cap_error_log = ramdump_phy_to_vir((unsigned long)RAMDUMP_CAP_LOG_BUF_ADDR, RAMDUMP_CAP_LOG_BUF_LEN); |
| cap_ddr_len_base = (unsigned int *)ramdump_phy_to_vir((unsigned long)IRAM_BASE_ADDR_BOOT_DDR, sizeof(unsigned long)); |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_init |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: RAMDUMP_SUCCESS or RAMDUMP_FAILED |
| * ÆäËü˵Ã÷: This function is used for ramdump init |
| *******************************************************************************/ |
| int __init ramdump_init(void) |
| { |
| int ret = 0; |
| ramdump_printf("Ramdump cap init start!!!!!\n"); |
| |
| if (ramdump_cap_init_flag == RAMDUMP_TRUE) |
| return RAMDUMP_SUCCESS; |
| ramdump_printf("Ramdump cap init rpmsg start!!!!!\n"); |
| ret = ramdump_cap_icp_init(); |
| if (ret != RAMDUMP_ICP_SUCCESS) |
| return ret; |
| |
| ramdump_register_callbacks(); |
| |
| ramdump_init_cmm_buf(); |
| |
| ramdump_init_sysctl_table(); |
| |
| ramdump_shared_mem_init(); |
| ramdump_oss_data_trans_init(); |
| |
| ramdump_printf("Ramdump cap init success!\n"); |
| ramdump_cap_init_flag = RAMDUMP_TRUE; |
| |
| return RAMDUMP_SUCCESS; |
| } |
| |
| /******************************************************************************* |
| * ¹¦ÄÜÃèÊö: ramdump_entry |
| * ²ÎÊý˵Ã÷: |
| * (´«Èë²ÎÊý) void |
| * (´«³ö²ÎÊý) void |
| * ·µ »Ø Öµ: void |
| * ÆäËü˵Ã÷: This function is used for ramdump entry |
| *******************************************************************************/ |
| void ramdump_entry (void) |
| { |
| unsigned long flags; |
| if (sysctl_ramdump_on_panic == false) |
| return; |
| |
| /* |
| * we need lock the irq, this can`t be interrupt. |
| */ |
| ramdump_irq_lock(flags); |
| |
| if (!ramdump_cap_init_flag) |
| while(true); /* endless circle */ |
| |
| if (++ramdump_count > 1) |
| while(true); /* endless circle */ |
| |
| /* |
| * save all regs first. |
| */ |
| ramdump_arch_save_all_regs(); |
| // generate error log |
| ramdump_cap_error_log_create(); |
| |
| //Éú³Écmm½Å±¾µÄµ¼³öÅäÖà |
| ramdump_cap_cmm_create(); |
| |
| /* notify client ramdump */ |
| ramdump_notify_server_panic(); |
| |
| ramdump_arch_clean_caches(); |
| ramdump_export_mode = *(unsigned int *)ramdump_export_flag_base; |
| |
| if((ramdump_export_mode == RAMDUMP_MODE_EMMC) |
| || (ramdump_export_mode == RAMDUMP_MODE_SPINAND)) |
| ramdump_data_transfer_to_device(); |
| |
| while(true) |
| ; |
| } |
| |
| #ifdef __cplusplus |
| } |
| #endif |
| |